%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <math.h>
%}

%token CTE_STRING CTE_INT CTE_FLOAT PUNTOYCOMA DOSPUNTOS COMA INICORCHETE
%token FINCORCHETE INIPARENTESIS FINPARENTESIS INILLAVE FINLLAVE COMILLA
%token CADENA AND OR NEGACION MAYOR MAYORIGUAL MENOR MENORIGUAL IGUALIGUAL DISTINTO
%token SUMA 
%token MULTIPLICACION 
%token DIVISION 
%left RESTA
%right IGUAL 
%token VARIABLE DEFINE ENDDEFINE
%token FLOAT ENTERO STRING WHILE ENDWHILE IF ELSE ENDIF PRINT RENAME ROUND TRUNC MAIN ENDMAIN
%token CONSTANTEBASE2 CONSTANTEBASE16

%start PROGRAMA

%%
PROGRAMA:
{printf("%d --> Inicio\n",syntaxLeido++);}
DECLARACIONES PRINCIPAL |
PRINCIPAL ;

DECLARACIONES:
DEFINE BLOQUEDECLARACION ENDDEFINE |
DEFINE BLOQUEDECLARACION ENDDEFINE DECLARACIONES ;

BLOQUEDECLARACION:
DECLARACION |
DECLARACION BLOQUEDECLARACION
{cantVariablesDeclaradas = 0;};

DECLARACION:
TIPODATO DOSPUNTOS LISTAVARIABLES ;

TIPODATO:
FLOAT
{
 inicializarTipos(FLOAT);	
} |
ENTERO
{
 inicializarTipos(ENTERO);
} |
STRING
{
 inicializarTipos(STRING);
} ;

LISTAVARIABLES:
VARIABLE
{ declararVariable($1);
  limpiarTipos();
  cantVariablesDeclaradas++;
} |
VARIABLE
{
  declararVariable($1);
  cantVariablesDeclaradas++;
}
COMA LISTAVARIABLES ;

PRINCIPAL:
MAIN
{
 printf("%d --> Inicio del Programa Principal\n",syntaxLeido++);
}
SENTENCIAS
{
 printf("%d --> Fin del Programa Principal\n",syntaxLeido++);
}
ENDMAIN ;

SENTENCIAS:
SENTENCIA |
SENTENCIAS SENTENCIA ;

SENTENCIASBLOQUE:
SENTENCIABLOQUE |
SENTENCIASBLOQUE SENTENCIABLOQUE ;

SENTENCIA:
ITERACION |
DECISION |
ASIGNACION |
OUTPUT |
FUNCIONRENAME ;

SENTENCIABLOQUE:
ITERACION |
DECISION |
ASIGNACION |
OUTPUT;

ITERACION:
WHILE
{
 printf("%d --> Comienzo de Iteracion\n",syntaxLeido++);
}
INIPARENTESIS 
{
	cIndice = contadorTercetos+1; 
	apilarNroTerceto(contadorTercetos+1);
}	
CONDICIONES FINPARENTESIS BLOQUE
{
 printf("%d --> Fin de Iteracion\n",syntaxLeido++);
}
ENDWHILE 
{
	char indiceTerceto[100];
	int tercetoCreado = 0;	
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	tercetoCreado = crearTerceto("JI",indiceTerceto,"---");
	
	
	sprintf(indiceTerceto,"[%i]",tercetoCreado+1);
	resolverUltimoCondicional(3,indiceTerceto);
	
	//si tenemos una condicion con AND debemos hacer reemplazo de 2 condiciones
	printf("REEMPLAZO DE AND EN WHILE %d",condicionAND);
	if(condicionAND > 0){
		resolverUltimoCondicional(3,indiceTerceto);
		condicionAND--;
	}
	
};

DECISION:
IF INIPARENTESIS CONDICIONES FINPARENTESIS BLOQUE ELSE
{	
	char indiceTerceto[100];	
	crearTerceto("JI","*REEMPLAZAR","---");
	//llamo a reemplazar a la incognita del condicional
	sprintf(indiceTerceto,"[%i]",contadorTercetos+1);	
	resolverUltimoCondicional(3,indiceTerceto);
	if(condicionAND > 0){
		resolverUltimoCondicional(3,indiceTerceto);
		condicionAND--;
	}
		
} BLOQUE ENDIF
{
	//llamo a reemplazar a la incognita despues del THEN q es la JI
	char indiceTerceto[100];	
	sprintf(indiceTerceto,"[%i]",contadorTercetos+1);	
	resolverUltimoCondicional(2,indiceTerceto);
}

| IF INIPARENTESIS CONDICIONES FINPARENTESIS BLOQUE ENDIF
{
	char *indiceTerceto;	
	sprintf(indiceTerceto,"[%i]",contadorTercetos+1);	
	resolverUltimoCondicional(3,indiceTerceto);
	if(condicionAND > 0){
		resolverUltimoCondicional(3,indiceTerceto);
		condicionAND--;
	}
};

ASIGNACION:
VARIABLE IGUAL EXPRESION PUNTOYCOMA
{
	char indiceTerceto[100];
	//Verifica si la variable esta declarada
	esVarDeclarada($1);
	esVarRenombrada($1);

   	printf("%d --> Asignacion a '%s' \n",syntaxLeido++, tablaSimbolos[$1].nombre);
	//Valida los tipos
	coincidenTipos($1, $3, 1);
	
	sprintf(indiceTerceto,"[%i]",eIndice);
	aIndice = crearTerceto("IGUAL",tablaSimbolos[$1].nombre,indiceTerceto);
	
};

OUTPUT:
PRINT INIPARENTESIS CTE_STRING
{
   printf("%d --> Impresion \n",syntaxLeido++);
	fIndice = crearTerceto("PRINT",tablaSimbolos[$3].nombre,"---");
}
FINPARENTESIS PUNTOYCOMA |
PRINT INIPARENTESIS VARIABLE
{
   printf("%d --> Impresion \n",syntaxLeido++);
   fIndice = crearTerceto("PRINT",tablaSimbolos[$3].nombre,"---");
}
FINPARENTESIS PUNTOYCOMA ;

FUNCIONROUND:
ROUND INIPARENTESIS EXPRESION 
{
	char indiceTercetoE[100];
	sprintf(indiceTercetoE,"[%i]",eIndice);
	fIndice = crearTerceto("ROUND",indiceTercetoE,"---");
} FINPARENTESIS;

FUNCIONTRUNC:
TRUNC INIPARENTESIS EXPRESION
{
	char indiceTercetoE[100];
	sprintf(indiceTercetoE,"[%i]",eIndice);
	fIndice = crearTerceto("TRUNC",indiceTercetoE,"---");
} FINPARENTESIS ;

FUNCIONRENAME:
RENAME INIPARENTESIS VARIABLE COMA VARIABLE
{
	renombrarVariable($3, $5);
}
FINPARENTESIS PUNTOYCOMA ;

EXPRESION:
TERMINO 
{
	printf("\nTerceto: expresion ---> termino");
	eIndice = tIndice;
}|
EXPRESION SUMA TERMINO
{
	char indiceTercetoE[100];
	char indiceTercetoT[100];
	
	//Valida los tipos
	coincidenTipos($1, $3, 0);
   	printf("%d --> Expresion SUMA \n",syntaxLeido++);
	
   	//printf("Valores %s %s\n",tablaSimbolos[$1].nombre,tablaSimbolos[$3].nombre);
	sprintf(indiceTercetoE,"[%i]",eIndice);
	sprintf(indiceTercetoT,"[%i]",tIndice);
	eIndice = crearTerceto("+",indiceTercetoE,indiceTercetoT);

} |
EXPRESION RESTA TERMINO
{
	char indiceTercetoE[100];
	char indiceTercetoT[100];
	
	//Valida los tipos
	coincidenTipos($1, $3,0);
   	printf("%d --> Expresion RESTA \n",syntaxLeido++);
	sprintf(indiceTercetoE,"[%i]",eIndice);
	sprintf(indiceTercetoT,"[%i]",tIndice);
	eIndice = crearTerceto("-",indiceTercetoE,indiceTercetoT);
//printf("Valores %s %s\n",tablaSimbolos[$1].nombre,tablaSimbolos[$3].nombre);
} ;

TERMINO:
FACTOR 
{
	tIndice = fIndice;
}|
TERMINO MULTIPLICACION FACTOR
{
 	char indiceTercetoF[100];
	char indiceTercetoT[100];
	//Valida los tipos
	coincidenTipos($1, $3,0);
   	printf("%d --> Termino MULTIPLICACION \n",syntaxLeido++);
	//printf("Valores %s %s\n",tablaSimbolos[$1].nombre,tablaSimbolos[$3].nombre);
	sprintf(indiceTercetoF,"[%i]",fIndice);
	sprintf(indiceTercetoT,"[%i]",tIndice);
	tIndice = crearTerceto("*",indiceTercetoT,indiceTercetoF);

} |
TERMINO DIVISION FACTOR
{
	char indiceTercetoF[100];
	char indiceTercetoT[100];
	//Valida los tipos
	coincidenTipos($1, $3,0);
   	printf("%d --> Termino DIVISION \n",syntaxLeido++);
	sprintf(indiceTercetoF,"[%i]",fIndice);
	sprintf(indiceTercetoT,"[%i]",tIndice);
	tIndice = crearTerceto("/",indiceTercetoT,indiceTercetoF);
//printf("Valores %s %s\n",tablaSimbolos[$1].nombre,tablaSimbolos[$3].nombre);
} ;

FACTOR:
VARIABLE
{
	fIndice = crearTerceto(tablaSimbolos[$1].nombre,"---","---");
	//Verifica si la variable esta declarada
	esVarDeclarada($1);
	esVarRenombrada($1);
}|
CONSTANTENUMERICA
{
	fIndice = crearTerceto(tablaSimbolos[$1].nombre,"---","---");	
}|
CTE_STRING
{
	fIndice = crearTerceto(tablaSimbolos[$1].nombre,"---","---");
}|
FUNCIONROUND 
{
	//fIndice = crearTerceto("ROUND",tablaSimbolos[$1].nombre,"---");
}|
FUNCIONTRUNC 
{
	//fIndice = crearTerceto("TRUNC",tablaSimbolos[$1].nombre,"---");
}| 
CONSTANTEBASE2
{
	fIndice = crearTerceto(tablaSimbolos[$1].nombre,"---","---");
}| 
CONSTANTEBASE16
{
	fIndice = crearTerceto(tablaSimbolos[$1].nombre,"---","---");
}| 
INIPARENTESIS EXPRESION FINPARENTESIS 
{
	tIndice = fIndice;
};

BLOQUE:
INILLAVE SENTENCIASBLOQUE FINLLAVE ;

CONDICIONES:
CONDICION 
{
	char indiceTerceto[100];
	char indiceTerceto2[100];
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	
	crearTerceto("CMP",indiceTerceto,indiceTerceto2);
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	crearTerceto(comparadorTerceto,indiceTerceto2,"*REEMPLAZAR");
	
}
| 
CONDICION 
{
	char indiceTerceto[100];
	char indiceTerceto2[100];
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	
	
	crearTerceto("CMP",indiceTerceto,indiceTerceto2);
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	crearTerceto(comparadorTerceto,indiceTerceto2,"*REEMPLAZAR");

}
AND CONDICION
{
    char indiceTerceto[100];
	char indiceTerceto2[100];
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
			printf("3condicion prendiendo AND\n");
	condicionAND++;

	
	crearTerceto("CMP",indiceTerceto,indiceTerceto2);
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	crearTerceto(comparadorTerceto,indiceTerceto2,"*REEMPLAZAR");
} 
| CONDICION 
{
	char indiceTerceto[100];
	char indiceTerceto2[100];
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	
	
	crearTerceto("CMP",indiceTerceto,indiceTerceto2);
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);

	//negamos el comparador, para que sea el original
	crearTerceto(negarComparador(comparadorTerceto),indiceTerceto2,"*REEMPLAZAR");
}
OR CONDICION
{
	char indiceTerceto[100];
	char indiceTerceto2[100];
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
		printf("5condicion prendiendo OR\n");

	condicionOR++;
	
	
	crearTerceto("CMP",indiceTerceto,indiceTerceto2);
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);

	//antes de agregar la proxima condicion, reemplazamos el salto del primer condicional para saltar 2 tercetos
	sprintf(indiceTerceto,"[%i]",contadorTercetos+2);	
	resolverUltimoCondicional(3,indiceTerceto);
	
	//creamos el segundo condicional	
	crearTerceto(comparadorTerceto,indiceTerceto2,"*REEMPLAZAR");
} |
NEGACION CONDICION
{
	char indiceTerceto[100];
	char indiceTerceto2[100];
    printf("%d --> Condicion NEGACION \n",syntaxLeido++);
		printf("6condicion prendiendo NOR\n");
	condicionNOT++;
	
	sprintf(indiceTerceto,"[%i]",desapilarNroTerceto());
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	
	crearTerceto("CMP",indiceTerceto,indiceTerceto2);
	
	sprintf(indiceTerceto2,"[%i]",contadorTercetos);
	crearTerceto(negarComparador(comparadorTerceto),indiceTerceto2,"*REEMPLAZAR");	
};

CONDICION:
INIPARENTESIS EXPRESION  COMPARADOR  EXPRESION FINPARENTESIS |
EXPRESION  COMPARADOR  EXPRESION;

COMPARADOR:
MAYOR{
    printf("%d --> Comparador MAYOR \n",syntaxLeido++);
	apilarNroTerceto(contadorTercetos);
	sprintf(comparadorTerceto,"JLE");
} |
MAYORIGUAL
{
    printf("%d --> Comparador MAYORIGUAL \n",syntaxLeido++);
	apilarNroTerceto(contadorTercetos);
	sprintf(comparadorTerceto,"JL");
} |
MENOR
{
    printf("%d --> Comparador MENOR \n",syntaxLeido++);
	apilarNroTerceto(contadorTercetos);
	sprintf(comparadorTerceto,"JGE");
	
} |
MENORIGUAL
{
    printf("%d --> Comparador MENORIGUAL \n",syntaxLeido++);
	apilarNroTerceto(contadorTercetos);
	sprintf(comparadorTerceto,"JG");
} |
DISTINTO
{
    printf("%d --> Comparador DISTINTO \n",syntaxLeido++);
	apilarNroTerceto(contadorTercetos);
	sprintf(comparadorTerceto,"JE");
} |
IGUALIGUAL
{
    printf("%d --> Comparador IGUALIGUAL \n",syntaxLeido++);
	apilarNroTerceto(contadorTercetos);
	sprintf(comparadorTerceto,"JNE");
};


CONSTANTENUMERICA:
CTE_INT|
CTE_FLOAT;

%%
/****************** Constantes *****************/
#define CANTIDAD_PALABRAS_RESERVADAS 16
#define CANTIDAD_MAX_TS	1000
#define ESTADO_INICIAL 0
#define ESTADO_FINAL 36
#define LARGO_MAX_TOKEN 35
#define LARGO_MAX_TOKEN_EXT 45
#define TAM_MAX_TOKENS 5000
#define TAM_MAX_CADENA 30
#define TAM_MAX_VAR 20
#define TRUE 1
#define FALSE 0
#define FLOAT_MAX_VALUE 65536 //16 BITS
#define REAL_MAX_VALUE FLT_MAX

/****************** Nros de columna para matriz de estados *****************/
#define COLUMNA_LETRA				 0
#define COLUMNA_DIGITO			 	 1
#define COLUMNA_SIMBOLO			 	 2
#define COLUMNA_PUNTO			 	 3
#define COLUMNA_DIVISION		 	 4
#define COLUMNA_NEGACION		 	 5
#define COLUMNA_COMILLAS		 	 6
#define COLUMNA_AND		       		 7
#define COLUMNA_OR		       	 	 8
#define COLUMNA_MENOR			 	 9
#define COLUMNA_MAYOR			 	 10
#define COLUMNA_IGUAL			 	 11
#define COLUMNA_SUMA			     12
#define COLUMNA_RESTA			 	 13
#define COLUMNA_MULTIPLICACION 	 	 14
#define COLUMNA_PUNTO_Y_COMA  	     15
#define COLUMNA_COMA			     16
#define COLUMNA_INI_BLOQUE		 	 17
#define COLUMNA_FIN_BLOQUE		 	 18
#define COLUMNA_INI_CORCHETE		 19
#define COLUMNA_FIN_CORCHETE		 20
#define COLUMNA_INI_PARENTESIS	 	 21
#define COLUMNA_FIN_PARENTESIS	 	 22
#define COLUMNA_DOS_PUNTOS 	 	 	 23
#define COLUMNA_BLANCO		 	 	 24

/****************** Rutinas semanticas *****************/
void iniVar();
void contVar();
void finVar();
void iniCteNum();
void contCteNum();
void finCteNum();
void iniCteString();
void contCteString();
void finCteString();
void error();
void opDivision();
void opNegacion();
void iniAnd();
void finAnd();
void iniOr();
void finOr();
void opMenor();
void opMayor();
void opIgual();
void opSuma();
void opResta();
void opMultiplicacion();
void puntoComa();
void coma();
void iniBloque();
void finBloque();
void iniCorchete();
void finCorchete();
void iniParentesis();
void finParentesis();
void nada();
void opMenorIgual();
void opMayorIgual();
void opDistinto();
void iniComent();
void contComent();
void posFinComent();
void finComent();
void posIniComent2();
void iniComent2();
void contComent2();
void posFinComent2();
void finComent2();
void puntoYComa();
void dosPuntos();
void opIgualIgual();
void finAnd();
void iniOr();
void finOr();
void iniCteOtra();
void contCteOtraValor();
void sepCteOtra();
void contCteOtraBase();
void finCteOtraBase2();
void finCteOtraBase16();

/****************** Funciones generica *****************/
void completarToken(int, int);
void analizarLexico(char *);
int inicializacion(char *);
FILE* abrirArchivo(char*, char);
int perteneceALaLista(char*, char);
void inicializarCadena();
void imprimirTablaSimbolos();
void imprimirTokens();
void convertirToken(int, char*, char*);
void calcularValorDecimalFromHexa(char*, int);
void calcularValorDecimalFromBina(char*, int);

/****************** Funciones semanticas *****************/
int yylex(void); //Llamado por yyparse
int yyerror(char *);
int yyparse(void); //Prototipo de yyparse
int getToken(void); //Parsea cada nuevo token. Devuelve el tipo de token reconocido (Antiguo yylex)
int getEvent(char); //Toma un caracter y devuelve el numero de columna de las matrices
int yylexCont = 0; //Contador de llamadas a yylex

/****************** Funciones Yacc *****************/
//Funciones para YACC
void declararVariable(int); 	 	//Marca una VARIABLE como declarada
void renombrarVariable(int, int); 	 	//Renombra una variable y la deja inaccesible
void setearTipoVar(int, char *); 	//Setea el tipo de las VARIABLES en la TS
void esVarDeclarada(int); 	 	   	//Verifica si la VARIABLE esta declarada
void esVarRenombrada(int); 	 	   	//Verifica si la VARIABLE esta renombrada
void coincidenTipos(int, int, int); 		//Verifica si coinciden los tipos de 2 VARIABLES
char * getStringErrorToken(int); 	//Obtiene el token esperado a partir del token pasado por parametro
void inicializarTipos(int); //Inicializa variables
void limpiarTipos();

//Funciones para Tercetos
int crearTerceto(char *, char *, char *);
void apilarNroTerceto(int);
int desapilarNroTerceto();
void guardarTercetos();
void resolverUltimoCondicional(int,char *);
char * negarComparador (char *);
int tercetoDevolverPosicionTS(char *);
char * convertirNroTercetoEnAuxiliar(char *);
int convertirNroTercetoEnEntero(char *);

//Funciones para Assembler
void generarAssembler();
void agregarSeccionDataASM (FILE *);
void agregarSeccionCodeASM (FILE *);
void addRutines(FILE *);



/****************** Estructuras *****************/
struct strTablaSimbolos {
	char nombre[LARGO_MAX_TOKEN_EXT];
	char tipo[20];
	int tipoToken;
	char valor[30];
	int longitud;
	char rename[LARGO_MAX_TOKEN_EXT];	
	int declarada;   
};

struct strTokens {
	int tipo;
	char valor[LARGO_MAX_TOKEN];
	int yylval;
    int nroLinea;
};
struct strPalabrasReservadas {
	char palabra[LARGO_MAX_TOKEN_EXT];
	int numero;
};

struct strTerceto {
	int numero;
	char elem1[LARGO_MAX_TOKEN_EXT];
	char elem2[LARGO_MAX_TOKEN_EXT];
	char elem3[LARGO_MAX_TOKEN_EXT];
	int deprecated;
};
/****************** Variables Globales *****************/
char cadena[TAM_MAX_CADENA];
FILE *fuente;
struct strTablaSimbolos tablaSimbolos[CANTIDAD_MAX_TS];
struct strTokens listaTokens[TAM_MAX_TOKENS];
struct strPalabrasReservadas reservadas[CANTIDAD_PALABRAS_RESERVADAS];
char caracterLeido;
int tipoToken;
int yylval;
int cantCaracteres;
char tokenGenerado[LARGO_MAX_TOKEN];
int cantTokens;
int leido;
int cantComentariosAbiertos;
int posUltimoSimbolo;
int lineaLeida = 1;
char generando[TAM_MAX_CADENA];
int tokenAnterior; //Es el token que se recibio antes del actual (utilizado en manejo de error)
int tokenActual; //Es el token actual (utilizado en manejo de error)
char valorDecimalConstate[TAM_MAX_CADENA];

//variables globales para generar tercetos
int contadorTercetos = 0; 
struct strTerceto listaTercetos[CANTIDAD_MAX_TS];
int eIndice = -1;
int aIndice = -1;
int tIndice = -1;
int fIndice = -1;
int cIndice = -1;
FILE *salidaTercetos;
int pilaTercetos[100];
int indicePilaTercetos = -1;
char comparadorTerceto[10];
char auxiliar[10] = { '\0', '\0', '\0', '\0', '\0','\0', '\0', '\0', '\0', '\0' };
char resultado[10] = { '\0', '\0', '\0', '\0', '\0','\0', '\0', '\0', '\0', '\0' };

int condicionAND = 0;
int condicionOR = 0;
int condicionNOT = 0;
int contadorConstantes = 0; //para generar los nombres de las constantes de la tabla de simbolos

int columna = 0;
/* Vector que almacenara el tipo de variable declarada
   0 = nada
   1 = Float
   2 = Entero
   3 = String
   estas seran posicionales.
*/
int tipoVariable  = 0;
int cantVariablesDeclaradas = 0;
int syntaxLeido = 0;

/****************** Arrays Globales *****************/
char letras[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
		'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\0' };
char digitos[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0' };
char simbolos[] = { '@', '#', '%', '$', '?', '~', '^', '\0' };
char blancos[] = { '\n', '\t', '\r', ' ', EOF, '\0' };

/***************** MATRICES *****************/
int nuevoEstado[37][26] = {
		{ 1, 2, 36, 3, 6, 34, 10, 12, 14, 16, 19, 21, 23, 24, 25, 26, 27, 28,
				29, 30, 31, 32, 33, 35, 0 }, //0
		{ 1, 1, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 2, 36, 3, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36 },
		{ 36, 3, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36 },
		{ 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
				5, 5 },
		{ 5, 5, 5, 5, 7, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
				5, 5 }, //5
		{ 36, 36, 36, 36, 36, 5, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36 },
		{ 5, 5, 5, 5, 7, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
				5, 5 },
		{ 8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
				8, 8 },
		{ 8, 8, 8, 8, 5, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
				8, 8 },
		{ 10, 10, 10, 10, 10, 10, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
				10, 10, 10, 10, 10, 10, 10, 10 }, //10
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 13, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 15, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, //15
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 17, 18, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 20, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, //20
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 22, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, { 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, //25
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, { 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36 }, { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, //30
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, { 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36 }, { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36 }, { 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36 },
		{ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
				36, 36, 36, 36, 36, 36, 36, 36 }, //35
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
				0, 0 } };

void (*proceso[37][26])()= {
	{	iniVar,iniCteNum,error,iniCteNum,opDivision,opNegacion,iniCteString,iniAnd,iniOr,opMenor,opMayor,opIgual,opSuma,opResta,opMultiplicacion,puntoYComa,coma,iniBloque,finBloque,iniCorchete,finCorchete,iniParentesis,finParentesis,dosPuntos,nada},
	{	contVar,contVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar,finVar}, //2
	{	finCteNum,contCteNum,finCteNum,contCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum}, //3
	{	finCteNum,contCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum,finCteNum}, //4
	{	contComent,contComent,contComent,contComent,finComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent}, //5
	{	contComent,contComent,contComent,contComent,posIniComent2,posFinComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent},
	{	nada,nada,nada,nada,nada,iniComent,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	contComent,contComent,contComent,contComent,posIniComent2,iniComent2,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent,contComent},
	{	contComent2,contComent2,contComent2,contComent2,contComent2,posFinComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2},
	{	contComent2,contComent2,contComent2,contComent2,finComent2,posFinComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2,contComent2}, //10
	{	contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString,contCteString},
	{	finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString,finCteString},
	{	error,error,error,error,error,error,error,finAnd,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	error,error,error,error,error,error,error,error,finOr,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}, //15
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,opDistinto,opMenorIgual,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,opMayorIgual,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}, //20
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,opIgualIgual,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}, //25
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}, //30
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}, //35
	{	nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada}
};


/***************** PROGRAMA *****************/
int main(int argc, char *argv[]) {
	char nombreArchivo[200] = "Entrada.txt";
	int result;

	//Llamada al AL
	analizarLexico(nombreArchivo);
	//Llamada al AS
	result = yyparse();

	if(result == 0) {
    
		
		//guardamos los tercetos generados en un archivo
		guardarTercetos(); //FIXME Guardar tercetos optimiza la tabla de tercetos y eso lo usa la generacion de ASM!!!!
		
		//Imprimo por pantalla y a un archivo la TS
		imprimirTablaSimbolos();
		
		//generacion de AMS
		generarAssembler();
    }

	getch();

	return EXIT_SUCCESS;
}

//En el lexico, yylex iba parseando un token por vez.
//Ahora los tokens los parsea en su totalidad analizarLexico , y luego yylex los ira entregando de a uno al ser invocada.
int yylex(void) {
	int tipoToken;

   if (yylexCont > cantTokens) {
   		return EXIT_SUCCESS;
   }

	// Recorre la lista de tokens obtenidos por analizarLexico.
	yylval = listaTokens[yylexCont].yylval;
	tipoToken = listaTokens[yylexCont].tipo;
	tokenAnterior = tokenActual;
	tokenActual = tipoToken;

	//Llevo la cuenta de las lineas que voy leyendo.
	if(listaTokens[yylexCont].nroLinea > 0) {
		lineaLeida = listaTokens[yylexCont].nroLinea;
	}

	// Se incrementa el contador de llamados a yylex.
  	yylexCont++;
  	return(tipoToken);
}

//Esta funcion es la que analizara los tokens y cargara la listaTokens.
void analizarLexico(char* nombreArchivo) {

	if(inicializacion(nombreArchivo) == 1 ) {
     	printf("ERROR: No se pudo abrir el archivo fuente.\n");
		getch();
		exit(1);
   }

   while(!feof(fuente)){
		if(leido == FALSE) {
      	caracterLeido = (char)getc(fuente);
         // suma las lineas del archivo ingresado
			if (caracterLeido == '\n') {
				lineaLeida++;
			}
		}
		// Carga el tipo de Token obtenido.
		listaTokens[cantTokens].tipo = getToken();
		if (listaTokens[cantTokens].tipo != 0)
		{
			//Carga el valor del Token
     	  	strcpy(listaTokens[cantTokens].valor, tokenGenerado);
     		//Carga la posicion en tabla de simbolos
    		listaTokens[cantTokens].yylval = yylval;
     		//Carga la linea del archivo donde esta el token
			listaTokens[cantTokens].nroLinea = lineaLeida;
  	  		//Se incrementa el contador de tokens
     	  	cantTokens++;
		}
	}
  	fclose(fuente);
}

//Inicializa la lista de palabras reservadas y los contadores.
int inicializacion(char * nombreArchivo) {

	if ((fuente = abrirArchivo(nombreArchivo, 'L')) == NULL) {
		return EXIT_FAILURE;
	}

	// Inicializa la lista de palabras reservadas
	strcpy(reservadas[0].palabra, "DEFINE");
	reservadas[0].numero = DEFINE;
	strcpy(reservadas[1].palabra, "ENDDEFINE");
	reservadas[1].numero = ENDDEFINE;
	strcpy(reservadas[2].palabra, "FLOAT");
	reservadas[2].numero = FLOAT;
	strcpy(reservadas[3].palabra, "ENTERO");
	reservadas[3].numero = ENTERO;
	strcpy(reservadas[4].palabra, "STRING");
	reservadas[4].numero = STRING;
	strcpy(reservadas[5].palabra, "WHILE");
	reservadas[5].numero = WHILE;
	strcpy(reservadas[6].palabra, "ENDWHILE");
	reservadas[6].numero = ENDWHILE;
	strcpy(reservadas[7].palabra, "IF");
	reservadas[7].numero = IF;
	strcpy(reservadas[8].palabra, "ELSE");
	reservadas[8].numero = ELSE;
	strcpy(reservadas[9].palabra, "ENDIF");
	reservadas[9].numero = ENDIF;
	strcpy(reservadas[10].palabra, "PRINT");
	reservadas[10].numero = PRINT;
	strcpy(reservadas[11].palabra, "RENAME");
	reservadas[11].numero = RENAME;
	strcpy(reservadas[12].palabra, "ROUND");
	reservadas[12].numero = ROUND;
	strcpy(reservadas[13].palabra, "TRUNC");
	reservadas[13].numero = TRUNC;
	strcpy(reservadas[14].palabra, "MAIN");
	reservadas[14].numero = MAIN;
	strcpy(reservadas[15].palabra, "ENDMAIN");
	reservadas[15].numero = ENDMAIN;

	cantTokens = 0;
	cantCaracteres = 0;
	cantComentariosAbiertos = 0;
	posUltimoSimbolo = 0;
	inicializarCadena();

	return EXIT_SUCCESS;
}

FILE* abrirArchivo(char* nombreArchivo, char modo) {
	if (modo == 'L') {
		return (fopen(nombreArchivo, "r"));
	}
	return (fopen(nombreArchivo, "w"));
}

//Inicializa la cadena en su totalidad con \0.
void inicializarCadena() {
	int i;
	for (i = 0; i < TAM_MAX_CADENA; i++) {
		cadena[i] = '\0';
		generando[i] = '\0';
	}
}

//Este seria el yylex del analizador lexico.
int getToken() {
    //Inicializo variables por cada nuevo token
	int estado = ESTADO_INICIAL;
	int columna = -1;
	yylval = -1;
	tipoToken = 0;
	leido = FALSE;

	while (!feof(fuente) && estado != ESTADO_FINAL) {
		columna = getEvent(caracterLeido);

      (proceso[estado][columna])();
		estado = nuevoEstado[estado][columna];

    	if(leido == FALSE) {
      	caracterLeido = (char)getc(fuente);
         // suma las lineas del archivo ingresado
			if (caracterLeido == '\n') {
				lineaLeida++;
			}
     	}
	}

	if(feof(fuente)) {
		columna = getEvent(caracterLeido);
		(proceso[estado][columna])();
		estado = nuevoEstado[estado][columna];
       //Verifica si los comentarios se encuentran correctamnete cerrados
       if(cantComentariosAbiertos > 0) {
			error();
		}
	}

	return tipoToken;
}

//Devuelve el nro de columna segun el tipo de caracter leido.
int getEvent(char caracterLeido) {

	if (perteneceALaLista(letras, caracterLeido)) {
		// printf("COLUMNA_LETRA\n");
		return (COLUMNA_LETRA);
	} else if (perteneceALaLista(digitos, caracterLeido)) {
		//printf("COLUMNA_DIGITO\n");
		return (COLUMNA_DIGITO);
	} else if (perteneceALaLista(simbolos, caracterLeido)) {
		//printf("COLUMNA_SIMBOLO\n");
		return (COLUMNA_SIMBOLO);
	} else if (perteneceALaLista(blancos, caracterLeido)) {
		//printf("COLUMNA_BLANCO\n");
		return (COLUMNA_BLANCO);
	}

	//Resto de los caracteres
	switch (caracterLeido) {
	case '+': { //printf("COLUMNA_SUMA\n");
		return (COLUMNA_SUMA);
	}
	case '-': { //printf("COLUMNA_RESTA\n");
		return (COLUMNA_RESTA);
	}
	case '*': { //printf("COLUMNA_MULTIPLICACION\n");
		return (COLUMNA_MULTIPLICACION);
	}
	case '/': { //printf("COLUMNA_DIVISION\n");
		return (COLUMNA_DIVISION);
	}
	case ';': { //printf("COLUMNA_PUNTO_Y_COMA\n");
		return (COLUMNA_PUNTO_Y_COMA);
	}
	case ',': { //printf("COLUMNA_COMA\n");
		return (COLUMNA_COMA);
	}
	case '.': { //printf("COLUMNA_PUNTO\n");
		return (COLUMNA_PUNTO);
	}
	case '"': { //printf("COLUMNA_COMILLAS\n");
		return (COLUMNA_COMILLAS);
	}
	case '>': { //printf("COLUMNA_MAYOR\n");
		return (COLUMNA_MAYOR);
	}
	case '<': { //printf("COLUMNA_MENOR\n");
		return (COLUMNA_MENOR);
	}
	case '=': { //printf("COLUMNA_IGUAL\n");
		return (COLUMNA_IGUAL);
	}
	case '(': { //printf("COLUMNA_INI_PARENTESIS\n");
		return (COLUMNA_INI_PARENTESIS);
	}
	case ')': { //printf("COLUMNA_FIN_PARENTESIS\n");
		return (COLUMNA_FIN_PARENTESIS);
	}
	case '{': { //printf("COLUMNA_INI_BLOQUE\n");
		return (COLUMNA_INI_BLOQUE);
	}
	case '}': { //printf("COLUMNA_FIN_BLOQUE\n");
		return (COLUMNA_FIN_BLOQUE);
	}
	case '[': { //printf("COLUMNA_INI_CORCHETE\n");
		return (COLUMNA_INI_CORCHETE);
	}
	case ']': { //printf("COLUMNA_FIN_CORCHETE\n");
		return (COLUMNA_FIN_CORCHETE);
	}
	case ':': { //printf("COLUMNA_DOS_PUNTOS\n");
		return (COLUMNA_DOS_PUNTOS);
	}
	case '!': { //printf("COLUMNA_NEGACION\n");
		return (COLUMNA_NEGACION);
	}
	case '&': { //printf("COLUMNA_AND\n");
		return (COLUMNA_AND);
	}
	case '|': { //printf("COLUMNA_OR\n");
		return (COLUMNA_OR);
	}
	}

	//Caracter no admitido por el lenguaje. Cortar Proceso.
	printf("ERROR ANALEX: Caracter '%c' no permitido.", caracterLeido);
	getch();
	exit(1);
}

int perteneceALaLista(char* lista, char caracterLeido) {
	int i;
	for (i = 0; lista[i] != '\0'; i++) {
		if (lista[i] == caracterLeido) {
			return 1;
		}
	}
	return 0;
}

int esPalabraReservada(char *c) {
	int i;
	for (i = 0; i < CANTIDAD_PALABRAS_RESERVADAS; i++) {
		// Compara las palabras, IMPLEMENTAR CASE SENSITIVE
		if (strcmp(reservadas[i].palabra, c) == 0) {
			return reservadas[i].numero;
		}
	}
	return FALSE;
}

//Ya no la usamamos mas.
void imprimirTokens() {
	FILE *fileTokens;
	char tokenFormateado[LARGO_MAX_TOKEN_EXT];
	int i, j = 0;
	//Abrir archivo para guardar la lista de tokens
	if ((fileTokens = abrirArchivo("ListaTokens.txt", 'E')) == NULL) {
		printf("ERROR: No se pudo abrir el archivo de salida de tokens.\n");
	}
	printf("Lista de Tokens\n\n");
	for (i = 0; i < cantTokens; i++) {
		convertirToken(listaTokens[i].tipo, listaTokens[i].valor,
				tokenFormateado);
		if (i == cantTokens - 1) {
			//Ultimo token
			printf("%-10d %s\n", i + 1, tokenFormateado);
			fprintf(fileTokens, "%-10d %s\n", i + 1, tokenFormateado); // Guardar en archivo
		} else {
			printf("%-10d %s\n", i + 1, tokenFormateado); //Pantalla
			fprintf(fileTokens, "%-10d %s\n", i + 1, tokenFormateado); // Guardar en archivo
		}
		if (j == 19) {
			j = 0;
			printf("Presione una tecla para continuar...\n");

		}
		j++;
	}
	fclose(fileTokens);
}

void imprimirTablaSimbolos() {
	FILE *fileSimbolos;
	int i;

	//Abrir archivo para guardar la tabla de simbolos
	if ((fileSimbolos = abrirArchivo("TablaSimbolos.txt", 'E')) == NULL) {
		printf(
				"ERROR: No se pudo abrir el archivo de salida de la tabla de simbolos.\n");
	}
	//Imprime la tabla de simbolos y guarda en archivo de salida
	printf("\n\nTabla de Simbolos\n");
	printf("%s%33s%20s%18s%18s\n", "Nombre", "Tipo", "Valor", "Longitud", "Rename");
	printf(
			"--------------------------------------------------------------------------------------------------------\n");
	fprintf(fileSimbolos, "%s%33s%20s%18s%18s\n", "Nombre", "Tipo", "Valor", "Longitud", "Rename");
	fprintf(
			fileSimbolos,
			"--------------------------------------------------------------------------------------------------------\n");
	for (i = 0; i < posUltimoSimbolo; i++) {
		if (tablaSimbolos[i].longitud > 0) {
			printf("%-35.33s%-19.17s%-15.13s%-15.0d%-35.33s\n", tablaSimbolos[i].nombre,
					tablaSimbolos[i].tipo, "-", tablaSimbolos[i].longitud,
					tablaSimbolos[i].rename);
			fprintf(fileSimbolos, "%-35.33s%-19.17s%-15.13s%-15.0d%-35.33s\n",
					tablaSimbolos[i].nombre, tablaSimbolos[i].tipo, "-",
					tablaSimbolos[i].longitud, tablaSimbolos[i].rename);
		} else {
			printf("%-35.33s%-19.17s%-15.13s%-15s%-35.33s\n", tablaSimbolos[i].nombre,
					tablaSimbolos[i].tipo, tablaSimbolos[i].valor, "-",
					tablaSimbolos[i].rename);
			fprintf(fileSimbolos, "%-35.33s%-19.17s%-15.13s%-15s%-35.33s\n",
					tablaSimbolos[i].nombre, tablaSimbolos[i].tipo,
					tablaSimbolos[i].valor, "-", tablaSimbolos[i].rename);
		}
	}
	fclose(fileSimbolos);
}

int buscarTS(char *simbolo) {
	int i;
	for (i = 0; i < posUltimoSimbolo; i++) {
		if (strcmp(tablaSimbolos[i].nombre, simbolo) == 0) {
			return (i);
		}
	}
	return (-1);
}

char * buscarTSPorAlias(char * aliasSimbolo) {
	int i;
	for (i = 0; i < posUltimoSimbolo; i++) {
		if (strcmp(tablaSimbolos[i].rename, aliasSimbolo) == 0) {
			return tablaSimbolos[i].nombre;
		}
	}
	return "-";
}

int agregarTS(struct strTablaSimbolos simbolo) {

	//Se comprueba que el simbolo no exista
	if ((yylval = buscarTS(simbolo.nombre)) != -1) {
		return yylval; //Ya existe, no se agrega
	}
	//Se marca como no declarada
	simbolo.declarada = 0;
	//Se agrega a la tabla
	tablaSimbolos[posUltimoSimbolo] = simbolo;
	//Se guarda la posicion donde se agrego
	yylval = posUltimoSimbolo;
	//Se incrementa el contador de simbolos
	posUltimoSimbolo++;
	return (posUltimoSimbolo - 1);
}

void convertirToken(int tipoToken, char *valor, char *salida) {
	int i;
	//Inicializa la salida
	for (i = 0; i < LARGO_MAX_TOKEN_EXT; i++) {
		salida[i] = '\0';
	}
	salida[0] = '<';
	salida[1] = ' ';
	if (tipoToken == VARIABLE) {
		//Variable
		strcat(salida, "ID:");
		strcat(salida, valor);
	} else {
		if (DEFINE <= tipoToken && ENDMAIN >= tipoToken) {
			//Palabra reservada
			strcat(salida, "RSV:");
			strcat(salida, valor);
		} else {
			if (tipoToken == CONSTANTEBASE2) {
				//Palabra reservada
				strcat(salida, "CTE_BASE_2:");
				strcat(salida, valor);
			} else {
				if (tipoToken == CONSTANTEBASE16) {
					//Palabra reservada
					strcat(salida, "CTE_BASE_16:");
					strcat(salida, valor);
				} else {
					//Otro
					strcat(salida, valor);
				}
			}
		}
	}
	strcat(salida, " >");
}

/****************** Funciones Yacc *****************/
int yyerror(char *cMsg) {
	int i;
	printf("\n Token Actual: %d.", tokenActual );
	printf("\n Token Anterior: %d.", tokenAnterior );
	printf("\n*** %s ***.\nLinea: %d. ", cMsg , lineaLeida);
	printf("No se esperaba %s luego de %s.\n", getStringErrorToken(tokenActual), getStringErrorToken(tokenAnterior));
	printf("--> ");
	for(i = 0; i < cantTokens; i++) {
	if(listaTokens[i].nroLinea == lineaLeida)
		printf("%s ", listaTokens[i].valor);
	}
	printf("\n\n");
	return 0;
}

char * getStringErrorToken(int numeroToken) {
	switch(numeroToken) {
		case DEFINE: return "la palabra reservada DEFINE";
		case ENDDEFINE: return "la palabra reservada ENDDEFINE";
		case WHILE: return "la palabra reservada WHILE";
		case ENDWHILE: return "la palabra reservada ENDWHILE";
		case IF: return "la palabra reservada IF";
		case ENDIF: return "la palabra reservada ENDIF";
		case PRINT: return "la palabra reservada PRINT";
		case ROUND: return "la palabra reservada ROUND";
		case TRUNC: return "la palabra reservada TRUNC";
		case RENAME: return "la palabra reservada RENAME";
		case MAIN: return "la palabra reservada MAIN";
		case ENDMAIN: return "la palabra reservada ENDMAIN";
		case CTE_INT: return "la Constante Entera";
		case CTE_FLOAT: return "la Constante Float";
		case CTE_STRING: return "la Constante String";
		case VARIABLE: return "la VARIABLE";
		case ENTERO: return "un ENTERO";
		case FLOAT: return "un FLOAT";
		case STRING: return "un STRING";
		case INILLAVE: return "'{'";
		case FINLLAVE: return "'}'";
		case INICORCHETE: return "'['";
		case FINCORCHETE: return "']'";
		case INIPARENTESIS: return "'('";
		case FINPARENTESIS: return "')'";
		case COMA: return "','";
		case PUNTOYCOMA: return "';'";
		case MULTIPLICACION: return "'*'";
		case DIVISION: return "'/'";
		case SUMA: return "'+'";
		case RESTA: return "'-'";
		case IGUAL: return "'='";
		case IGUALIGUAL: return "'=='";
		case MAYOR: return "'>'";
		case MENOR: return "'<'";
		case MAYORIGUAL: return "'>='";
		case MENORIGUAL: return "'<='";
		case DISTINTO: return "'<>'";
		case NEGACION: return "'!'";
		case AND: return "'&&'";
		case OR: return "'||'";
	}
	return "token no encontrado";
}

void declararVariable(int posVar) {
	
	if (posVar > -1) {
		// Se marca la variable como declarada
		tablaSimbolos[posVar].declarada++;	
	}	
	
  	if (tablaSimbolos[posVar].declarada > 1) {
		// La variable ya estaba declarada
		printf("\nSYNTAX ERROR. Variable %s previamente declarada. Linea: %d.\n", tablaSimbolos[posVar].nombre, lineaLeida);
		getch();
		exit(1);
	}

   if(tipoVariable == FLOAT){
     printf("%d --> Declaracion variable '%s' y asignacion de tipo Float \n",syntaxLeido++,tablaSimbolos[posVar].nombre);
     tablaSimbolos[posVar].tipoToken = FLOAT;
 	  strcpy(tablaSimbolos[posVar].tipo, "FLOAT");
   } else if(tipoVariable == ENTERO){
     printf("%d --> Declaracion variable '%s' y asignacion de tipo Entero \n",syntaxLeido++,tablaSimbolos[posVar].nombre);
     tablaSimbolos[posVar].tipoToken = ENTERO;
 	  strcpy(tablaSimbolos[posVar].tipo, "ENTERO");
   } if(tipoVariable == STRING){
     printf("%d --> Declaracion variable '%s' y asignacion de tipo String \n",syntaxLeido++,tablaSimbolos[posVar].nombre);
     tablaSimbolos[posVar].tipoToken = STRING;
 	  strcpy(tablaSimbolos[posVar].tipo, "STRING");
   }

}

void renombrarVariable(int posVar1, int posVar2) {
		
  	if (tablaSimbolos[posVar2].declarada >= 1) {
		// La variable ya estaba declarada
		printf("\nSYNTAX ERROR. Variable %s previamente declarada. Linea: %d.\n", tablaSimbolos[posVar2].nombre, lineaLeida);
		getch();
		exit(1);
	}
	//Copio los valores de la variable renombrada
	strcpy(tablaSimbolos[posVar2].tipo, tablaSimbolos[posVar1].tipo);
	strcpy(tablaSimbolos[posVar2].valor, tablaSimbolos[posVar1].valor);
	tablaSimbolos[posVar2].longitud = tablaSimbolos[posVar1].longitud;
	tablaSimbolos[posVar2].tipoToken = tablaSimbolos[posVar1].tipoToken;
	tablaSimbolos[posVar2].declarada = tablaSimbolos[posVar1].declarada;
	strcpy(tablaSimbolos[posVar2].rename,"-");

	
	//Asigno el valor del rename a la variable renombrada
	strcpy(tablaSimbolos[posVar1].rename, tablaSimbolos[posVar2].nombre);
}
//Recorre las variables y les asigna el tipo
void setearTipoVar(int tipo, char *descripcion) {
	int i;
	// Recorre las variables declaradas y aun sin tipo de la tabla de simbolos
 	for (i = 0; i < posUltimoSimbolo; i++) {
 		if (tablaSimbolos[i].tipoToken == 0  && tablaSimbolos[i].declarada == 1) {
 			tablaSimbolos[i].tipoToken = tipo;
 			strcpy(tablaSimbolos[i].tipo, descripcion);
 		}
	}
	
}

//Comprueba que las variables esten declaradas.
void esVarDeclarada(int posVar) {
	if (tablaSimbolos[posVar].declarada == 0) {
		// Variable no declarada
		printf("\nSYNTAX ERROR. Variable %s no declarada. Linea: %d\n", tablaSimbolos[posVar].nombre, lineaLeida);
		getch();
		exit(1);
	}
}

//Comprueba que las variables no esten renombradas.
void esVarRenombrada(int posVar) {
	if (strcmp(tablaSimbolos[posVar].rename, "-") != 0) {
		// Variable no declarada
		printf("\nSYNTAX ERROR. Variable %s ha sido renombrada y es inaccesible. Linea: %d", tablaSimbolos[posVar].nombre, lineaLeida);
		printf("\nSYNTAX ERROR. El nuevo nombre de la variable es %s \n", tablaSimbolos[posVar].rename);
		getch();
		exit(1);
	}
}

//Distingue entre los tipos de operaciones --> 0 : operacion , 1: Asignacion
void coincidenTipos(int pos1, int pos2, int operacion) {
	int tipo1 = tablaSimbolos[pos1].tipoToken;
	int tipo2 = tablaSimbolos[pos2].tipoToken;
	// printf("Tipo1: %d\n", tipo1);
	// printf("Tipo2: %d\n", tipo2);
	
	if ( operacion == 0)
	{	if (tipo1 != tipo2) 
		{
			if((tipo1 == FLOAT && tipo2 != ENTERO) || (tipo2 == ENTERO && tipo1 != FLOAT))					
			{
				//Distintos tipos de variable
				printf("\nSYNTAX ERROR. No coinciden los tipos entre %s y %s. Linea: %d.\n", tablaSimbolos[pos1].nombre, tablaSimbolos[pos2].nombre, lineaLeida);
				getch();
				exit(1);
			} 
		}
	}	
	else	
	{
		if((tipo1 == ENTERO && tipo2 != ENTERO))					
		{
			//Distintos tipos de variable
			printf("\nSYNTAX ERROR. No coinciden los tipos entre %s y %s. Linea: %d.\n", tablaSimbolos[pos1].nombre, tablaSimbolos[pos2].nombre, lineaLeida);
			getch();
			exit(1);		 
		}	
	}	
}

void iniVar() {
	//  printf(" \n iniVar,");
	cantCaracteres = 1;
	inicializarCadena();
	strcpy(generando, "Variable o Palabra Reservada");
	cadena[cantCaracteres - 1] = caracterLeido;
}

void contVar() {
	//  printf(" contVar,");
	cantCaracteres++;
	cadena[cantCaracteres - 1] = caracterLeido;
}

void finVar() {
	//  printf("finVar \n");
	struct strTablaSimbolos simbolo;

	leido = TRUE; //Indica que no debe leerse otro caracter

	//Se verifica si es una palabra reservada
	if ((tipoToken = esPalabraReservada(cadena)) != 0) {
		strcpy(tokenGenerado, cadena);
		return; //Se vuelve, no hay que agregar a la TS
	}

	tipoToken = VARIABLE;

	// printf("token: %s\n", cadena);
	if (cantCaracteres > TAM_MAX_VAR) {
		printf("\nERROR ANALEX: La variable '%s' excede la cantidad maxima de caracteres permitidos(%d).\n", cadena, TAM_MAX_VAR);
		getch();
		exit(1);
	}
	strcpy(tokenGenerado, cadena);
	//Agregar a TS
	strcpy(simbolo.nombre, tokenGenerado);
	strcpy(simbolo.tipo, ""); //Se setea en el analisis sintactico
	simbolo.tipoToken = 0;	  //Se setea en el analisis sintactico
	simbolo.longitud = 0;
	strcpy(simbolo.valor, "-");
	strcpy(simbolo.rename, "-");
	agregarTS(simbolo);
}

void iniCteNum() {
	// printf("\n iniCteNum,");
	cantCaracteres = 1;
	inicializarCadena();
	strcpy(generando, "Constante Numerica");
	cadena[cantCaracteres - 1] = caracterLeido;
}

void contCteNum() {
	//printf(" iniCteNum,");
	cantCaracteres++;
	if (cantCaracteres == TAM_MAX_CADENA) {
		printf("ERROR ANALEX: El valor '%s' esta fuera del rango numerico permitido(%d). \n", cadena, TAM_MAX_VAR);
		getch();
		exit(1);
	}
	cadena[cantCaracteres - 1] = caracterLeido;
}

void finCteNum() {
	//printf("f inCteNum\n");
	//Manejo todas las constantes numericas como float
	float valor;
	char** pointer = NULL;
	struct strTablaSimbolos simbolo;
	int i;
	char nombreConstante[100];
	leido = TRUE; //Indica que no debe leerse otro caracter

	strcpy(tokenGenerado, cadena);

	//Convierto la cadena a float
	valor = strtod(cadena, pointer);
	if (valor < 0) {
		valor *= -1;
	}

	//Verificar si se esta fuera del rango del float
	if (valor > FLOAT_MAX_VALUE) { // FLT_MAX
		printf("\nANALEX ERROR: El valor '%s' esta fuera del rango numerico permitido (%d). Linea %d.\n",
								cadena, FLOAT_MAX_VALUE, lineaLeida);
		getch();
		exit(1);
	}

	for (i = 0; tokenGenerado[i] != '\0'; i++) {
		if (tokenGenerado[i] == '.') {
			tipoToken = CTE_FLOAT;
			strcpy(simbolo.tipo, "CTE_FLOAT");
			simbolo.tipoToken = FLOAT; 
			break;
		} else {
			tipoToken = CTE_INT;
			strcpy(simbolo.tipo, "CTE_INT");
			simbolo.tipoToken = ENTERO; 
		}
	}

	strcpy(tokenGenerado, cadena);

	//Agregar a TS
	contadorConstantes++;	
	sprintf(nombreConstante,"_CTE%i",contadorConstantes);
	
	strcpy(simbolo.nombre, nombreConstante);
	strcpy(simbolo.valor, tokenGenerado);
	simbolo.longitud = 0;
	strcpy(simbolo.rename, "-");
	agregarTS(simbolo);
}

void iniCteString() {
	//printf("\n iniCteString,");
	cantCaracteres = 1;
	inicializarCadena();
	strcpy(generando, "Constante String");
	cadena[cantCaracteres - 1] = caracterLeido;
}

void contCteString() {
	//printf(" contCteString,");
	cantCaracteres++;

	if (cantCaracteres == TAM_MAX_CADENA) {
		printf(
				"ERROR ANALEX: La constante '%s' excede la cantidad maxima de caracteres permitidos para un string (%d).\n",
				cadena, TAM_MAX_CADENA);
		//
		getch();
		exit(1);
	}
	cadena[cantCaracteres - 1] = caracterLeido;
}

void finCteString() {
	//printf("finCteString\n");
	struct strTablaSimbolos simbolo;
	char nombreConstante[100];
	tipoToken = CTE_STRING;
	strcpy(tokenGenerado, cadena);

	//Agregar a TS
	contadorConstantes++;
	sprintf(nombreConstante,"_CTE%i",contadorConstantes);
	
	strcpy(simbolo.nombre, nombreConstante);
	strcpy(simbolo.tipo, "CTE_STRING");
	simbolo.tipoToken = STRING; 
	strcpy(simbolo.valor, tokenGenerado);
	simbolo.longitud = cantCaracteres - 2; // no cuento las dos doble comillas
	strcpy(simbolo.rename, "-");
	agregarTS(simbolo);
	leido = TRUE; //Indica que no debe leerse otro caracter
}

void opSuma() {
	//printf("opSuma\n");
	completarToken(1, SUMA);
}

void opResta() {
	//printf("opResta\n");
	completarToken(1, RESTA);
}

void opMultiplicacion() {
	//printf("opMultiplicacion\n");
	completarToken(1, MULTIPLICACION);
}

void opDivision() {
	//printf("opDivision\n");
	completarToken(1, DIVISION);
}

void iniBloque() {
	//printf("iniBloque\n");
	completarToken(1, INILLAVE);
}

void finBloque() {
	//printf("finBloque\n");
	completarToken(1, FINLLAVE);
}

void iniCorchete() {
	//printf("iniCorchete\n");
	completarToken(1, INICORCHETE);
}

void finCorchete() {
	//printf("finCorchete\n");
	completarToken(1, FINCORCHETE);
}

void coma() {
	//printf("coma\n");
	completarToken(1, COMA);
}

void dosPuntos() {
	//printf("dosPuntos\n");
	completarToken(1, DOSPUNTOS);
}

void opNegacion() {
	//printf("opNegacion\n");
	completarToken(1, NEGACION);
}

void opIgual() {
	// printf("opIgual\n");
	completarToken(1, IGUAL);
}

void opMayor() {
	//printf("opMayor\n");
	completarToken(1, MAYOR);
}

void opMenor() {
	//printf("opMenor\n");
	completarToken(1, MENOR);
}

void igualIgual() {
	// printf("igualIgual\n");
	completarToken(2, IGUALIGUAL);
}

void opMayorIgual() {
	// printf("opMayorIgual\n");
	completarToken(2, MAYORIGUAL);
}

void opMenorIgual() {
	//printf("opMenorIgual\n");
	completarToken(2, MENORIGUAL);
}

void opDistinto() {
	//printf("opDistinto\n");
	completarToken(2, DISTINTO);
}

void puntoYComa() {
	//	printf("puntoYComa\n");
	completarToken(1, PUNTOYCOMA);
}

void opIgualIgual() {
	//printf("opIgualIgual\n");
	completarToken(2, IGUALIGUAL);
}

void iniAnd() {
	//printf("iniAnd\n");
	completarToken(1, AND);
	strcpy(generando, "Operador AND");
}

void finAnd() {
	//printf("finAnd\n");
	completarToken(2, AND);
}

void iniOr() {
	//printf("iniOr\n");
	completarToken(1, OR);
	strcpy(generando, "Operador OR");
}

void finOr() {

	// printf("finOr\n");

	completarToken(2, OR);

}

void completarToken(int cantCarac, int tipo) {
	// printf("completarToken\n");
	tipoToken = tipo;
	if (cantCarac == 1) {
		inicializarCadena();
	}
	cantCaracteres = cantCarac;

	cadena[cantCaracteres - 1] = caracterLeido;
	strcpy(tokenGenerado, cadena);
}

void nada() {
	//printf("nada, ");
	if (leido == TRUE) {
		leido = FALSE;
	} else {
		leido = TRUE;
	}
}

void error() {
	//	printf("error\n");
	if (strcmp(generando, "") != 0) {
		printf("ERROR ANALEX: Generando %s, Linea %d\n.", generando, lineaLeida);
		getch();
		exit(1);
	} else {
		printf("ERROR ANALEX: Linea: %d , Caracter: %c\n", lineaLeida, caracterLeido);
		getch();
		exit(1);
	}
}

void iniComent() {
	//printf("iniComent\n");
	tipoToken = 0; //Limpio el tipoToken seteado por opDiv
	strcpy(generando, "Comentario Simple");
	cantComentariosAbiertos++; //Se abre un bloque

	if (cantComentariosAbiertos > 1) {
		printf("ERROR ANALEX: Error al crear comentario.\n");
		getch();
		exit(1);
	}
}

void contComent() {
	//printf("contComent\n");
	//Nada
}

void posFinComent() {
	// printf("posFinComent\n");
	//Nada
}

void finComent() {
	//printf("finComent\n");
	cantComentariosAbiertos--; //Se cierra un bloque

	if (cantComentariosAbiertos > 0) {
		printf("ERROR ANALEX: Error al crear comentario.\n");
		getch();
		exit(1);
	}
}

void posIniComent2() {
	//printf("posIniComent2\n");
	//Nada
}

void iniComent2() {
	// printf("iniComent2\n");
	cantComentariosAbiertos++; //Se abre un bloque
	strcpy(generando, "Comentario Anidado");
	if (cantComentariosAbiertos > 2) {
		printf("ERROR ANALEX: Error al crear comentario de segundo nivel.\n");
		getch();
		exit(1);
	}
}

void contComent2() {
	//printf("contComent2\n");
	//Nada
}

void posFinComent2() {
	//printf("posFinComent2\n");
	//Nada
}

void finComent2() {
	//printf("finComent2\n");
	cantComentariosAbiertos--; //Se cierra un bloque

	if (cantComentariosAbiertos > 1) {
		printf("ERROR ANALEX: Error al crear comentario de segundo nivel.\n");
		getch();
		exit(1);
	}
}

void inicializarTipos(int tipo){
   tipoVariable = tipo;
}

void limpiarTipos(){
   	tipoVariable = 0;
}

void calcularValorDecimalFromBina(char* cadena, int cantCaracteres)
{

	char NroHexa[TAM_MAX_CADENA]; 
	char Aux[2]; 
	int i, Error; 
	int NroDec; 
	long PosMult; 
	
	//Armo la cadena de la constante en otra base para obtener su valor en decimal.
	for (i = 0; i <= cantCaracteres; i++)
		NroHexa[i] = cadena[i];
		
	//printf("el numero convertido en binario es: %d\n", strlen(NroHexa) );
	
	// Chequeo que los caracteres del numero sean validos 
	for( Error = 0, i = strlen(NroHexa) - 1; i>=0; i--) 
	{ 
		if( ( NroHexa[i] != '0' && NroHexa[i] != '1' )) 
		{ 
			Error = 1; 
			break; 
		} 
	} 

	if( !Error ) 
	{ 
		for( NroDec = 0, i = strlen(NroHexa)-1; i>=0; i--) 
		{ 
			//printf("strlen:  %d", strlen(NroHexa) - 1 - i);
			PosMult = (long)pow( 2, (strlen(NroHexa) -1- i) ); 
			//printf("posmulti:  %ld", PosMult);
			if( PosMult == 0 ) 
				PosMult = 1; 
			
			switch( NroHexa[i] ) 
			{ 						
				case '1': 
					NroDec += 1 * PosMult; 
				break; 				 
				default: 
					Aux[0] = NroHexa[i]; 
					Aux[1] = '\0'; 
					NroDec += atoi( Aux ) * PosMult; 
				break; 
			}	 
		} 
		//printf( "El numero %s en Binario es %d\n", NroHexa, NroDec ); 
	} 
	else 
		printf( "El numero ingresado no es Binario\n" ); 
	getch();
	//Se convierte en char el valor calculado para asignarlo al simbolo.
	sprintf(valorDecimalConstate, "%d", NroDec);
	
}

void calcularValorDecimalFromHexa(char* cadena, int cantCaracteres)
{
	char NroHexa[TAM_MAX_CADENA]; 
	char Aux[2]; 
	int i, Error; 
	int NroDec; 
	long PosMult; 
	
	
	//Armo la cadena de la constante en otra base para obtener su valor en decimal.
	for (i = 0; i <= cantCaracteres; i++)
		NroHexa[i] = cadena[i];
			
	// Chequeo que los caracteres del numero sean validos 
	for( Error = 0, i = strlen(NroHexa) - 1; i>=0; i--) 
	{ 
		if( !( ( NroHexa[i] >= 'A' && NroHexa[i] <= 'F' ) || 
			( NroHexa[i] >= 'a' && NroHexa[i] <= 'f' ) || 
			( NroHexa[i] >= '0' && NroHexa[i] <= '9' ) ) ) 
		{ 
			Error = 1; 
			break; 
		} 
	} 

	if( !Error ) 
	{ 
	for( NroDec = 0, i = strlen(NroHexa)-1; i>=0; i--) 
	{ 
		//printf("strlen:  %d", strlen(NroHexa) - 1 - i);
		PosMult = (long)pow( 16, (strlen(NroHexa) -1- i) ); 
	
		if( PosMult == 0 ) 
			PosMult = 1; 
		
		switch( NroHexa[i] ) 
		{ 
			case 'A': 
			case 'a': 
				NroDec += 10 * PosMult; 
			break; 
			case 'B': 
			case 'b': 
				NroDec += 11 * PosMult; 
			break; 
			case 'C': 
			case 'c': 
				NroDec += 12 * PosMult; 
			break; 
			case 'D': 
			case 'd': 
				NroDec += 13 * PosMult; 
			break; 
			case 'E': 
			case 'e': 
				NroDec += 14 * PosMult; 
			break; 
			case 'F': 
			case 'f': 
				NroDec += 15 * PosMult; 
			break; 
			default: 
				Aux[0] = NroHexa[i]; 
				Aux[1] = '\0'; 
				NroDec += atoi( Aux ) * PosMult; 
			break; 
		}	 
	} 
	//printf( "El numero %s en decimal es %d\n", NroHexa, NroDec ); 
	} 
	else 
	printf( "El numero ingresado no es hexadecimal\n" ); 
	getch(); 
	//Se convierte en char el valor calculado para asignarlo al simbolo.
	sprintf(valorDecimalConstate,"%d",NroDec);

}
void iniParentesis() {

	//Guardo el parentesis que ya tengo parseado.
	char caracterLeidoAnterior = caracterLeido;
	int i = 0;
	char cadenaTemp[TAM_MAX_CADENA];
	char cadenaConstanteOtraBase[TAM_MAX_CADENA];
	//En este punto empieza el reconocimiento de una posible constante en otra base.
	//Leo el siguiente caracter.
	caracterLeido = (char) getc(fuente);

	//Si leo un espacio en blanco entonces solamente debo parsear el parentesis.	
	if (caracterLeido == ' ') { //Vuelvo el cursos un caracter hacia atras.
		ungetc(caracterLeido, fuente);
		caracterLeido = caracterLeidoAnterior;
		completarToken(1, INIPARENTESIS);

	} else { //En  este momento tenemos parseado un "INIPARENTESIS" y el siguiente caracter no es un espacio, por lo que consideramos
			 //que sea un posible inicio de constante en otra base.

		//Almaceno en una cadena temporal los caracteres que voy parseando.
		cantCaracteres = 2;
		cadenaTemp[0] = '('; // Agrego el parentesis como primer caracter.
		cadenaTemp[cantCaracteres - 1] = caracterLeido; //Agrego luego el caracter leido.

		//Empiezo a evaluar que tipo de token estoy parseando.
		//Leo el siguiente caracter.
		caracterLeido = (char) getc(fuente);
		while ((perteneceALaLista(letras, caracterLeido))
				|| (perteneceALaLista(digitos, caracterLeido))) {
			cantCaracteres++;
			cadenaTemp[cantCaracteres - 1] = caracterLeido;
			caracterLeido = (char) getc(fuente);
		}
		
		cantCaracteres++;
		cadenaTemp[cantCaracteres-1] = caracterLeido;

		//Si despues de la variable leo una coma, estoy en una constante en otra base o un rename.
		//Evaluo si el siguiente caracter es un digito, entonces es una constante en otra base.
		if (caracterLeido == ',') 
		{	
			caracterLeido = (char) getc(fuente);	
			cadenaTemp[cantCaracteres] = caracterLeido;			
			if(perteneceALaLista(digitos, caracterLeido))
			{	
				//Inicializo la cadena.
				for (i = 0; i < TAM_MAX_CADENA; i++)
					cadenaConstanteOtraBase[i] = '\0';
				//extraigo la constante en otra base para obtener su valor en decimal.
				for (i = 1; i <= cantCaracteres-2; i++)
					cadenaConstanteOtraBase[i-1] = cadenaTemp[i];
				
				//Segun el tipo de digito se llama a la funcion de base correspondiente.
				if( caracterLeido == '2' )
					calcularValorDecimalFromBina(cadenaConstanteOtraBase, cantCaracteres-2);
				else
					calcularValorDecimalFromHexa(cadenaConstanteOtraBase, cantCaracteres-2);
				
				//Inicializo la cadena que contendra la CEOB.
				inicializarCadena();
				strcpy(generando, "Constante en otra base.");
				for (i = 0; i <= cantCaracteres; i++)
					cadena[i] = cadenaTemp[i];
							
				contCteOtraBase();
			}
			else 
			{
				//Si no es un digito, no tengo una constante en otra base, por lo que hago el unget y tengo que reconocer solo el iniparentesis.
				for (i = cantCaracteres; i > 0; i--)
					ungetc(cadenaTemp[i], fuente);
				//Reconozco un INIPARENTESIS, cargo el valor de caracter leido y vuelvo al estado inicial.	
				caracterLeido = cadenaTemp[0];
				completarToken(1, INIPARENTESIS);				
			}
			
		} else {
			//Si no es coma, no tengo una constante en otra base, por lo que hago el unget y tengo que reconocer solo el iniparentesis.
			for (i = cantCaracteres-1; i > 0; i--)
				ungetc(cadenaTemp[i], fuente);
			//Reconozco un INIPARENTESIS, cargo el valor de caracter leido y vuelvo al estado inicial.	
			caracterLeido = cadenaTemp[0];
			completarToken(1, INIPARENTESIS);

		}

	}
}

//Esta funcion no la invoco mediante el automata, la invoco desde iniParentesis cuando reconozco constante en otra base.
void iniCteOtra() {
	//Llegado este punto, ya se que lo que estoy por parsear es una constante en otra base.
	//Tengo que inicializar la cadena y agregar el INI_PARENTESIS como primer caracter.
	printf("valor leido %c", caracterLeido);

	//Inicializo la cadena y copio el INI_PARENTESIS al inicio de la misma.
	inicializarCadena();
	strcpy(generando, "Constante en otra base.");
	cantCaracteres = 1;
	cadena[cantCaracteres - 1] = '(';

}

void contCteOtraValor() {

	cantCaracteres++;
	cadena[cantCaracteres - 1] = caracterLeido;
}

void sepCteOtra() {

	cantCaracteres++;
	cadena[cantCaracteres - 1] = caracterLeido;
}

void contCteOtraBase() {

	//En este metodo esta la logica que diferencia una constante en binario o hexa.
	if (caracterLeido == '2') {
		cantCaracteres++;
		cadena[cantCaracteres - 1] = caracterLeido;

		caracterLeido = (char) getc(fuente);
		finCteOtraBase2();
	} else {
		if (caracterLeido == '1') { //Almaceno el uno en la cadena.
			cantCaracteres++;
			cadena[cantCaracteres - 1] = caracterLeido;
			//Leo el otro caracter que tiene que ser un 6, sino error.
			caracterLeido = (char) getc(fuente);
			if (caracterLeido == '6') {
				cantCaracteres++;
				cadena[cantCaracteres - 1] = caracterLeido;

				caracterLeido = (char) getc(fuente);
				finCteOtraBase16();
			} else {
				error();
			}
		} else {
			error();
		}
	}
}

void finCteOtraBase2() {
	struct strTablaSimbolos simbolo;
	char nombreConstante[100];
	//printf("finConstOtra\n");
	//printf("\nleido %c",caracterLeido);
	cantCaracteres++;
	cadena[cantCaracteres - 1] = caracterLeido;
	tipoToken = CONSTANTEBASE2;
	completarToken(cantCaracteres, CONSTANTEBASE2);
	strcpy(tokenGenerado, cadena);

	//Agregar a TS
	contadorConstantes++;
	sprintf(nombreConstante,"_CTE%i",contadorConstantes);
	
	strcpy(simbolo.nombre, nombreConstante);
	strcpy(simbolo.tipo, "CTE_BASE_2");
	simbolo.tipoToken = ENTERO;
	//strcpy(simbolo.valor, tokenGenerado ); //Cargamos el valor decimal directamente.
	strcpy(simbolo.valor, valorDecimalConstate);
	simbolo.longitud = 0;
	strcpy(simbolo.rename, "-");
	agregarTS(simbolo);
	leido = FALSE; //Indica que no debe leerse otro caracter
}

void finCteOtraBase16() {
	struct strTablaSimbolos simbolo;
	char nombreConstante[100];
	//printf("finConstOtra\n");
	//printf("\nleido %c",caracterLeido);
	cantCaracteres++;
	cadena[cantCaracteres - 1] = caracterLeido;
	tipoToken = CONSTANTEBASE16;
	completarToken(cantCaracteres, CONSTANTEBASE16);
	strcpy(tokenGenerado, cadena);

	//Agregar a TS
	contadorConstantes++;
	sprintf(nombreConstante,"_CTE%i",contadorConstantes);
	
	strcpy(simbolo.nombre, nombreConstante);
	//valorDecimalCte = calcularValorDecimal(cadena,16)
	strcpy(simbolo.tipo, "CTE_BASE_16");
	simbolo.tipoToken = ENTERO;
	//strcpy(simbolo.valor, tokenGenerado ); //Cargamos el valor decimal directamente.
	strcpy(simbolo.valor, valorDecimalConstate);
	simbolo.longitud = 0;
	strcpy(simbolo.rename, "-");
	agregarTS(simbolo);
	leido = FALSE; //Indica que no debe leerse otro caracter
}

void finParentesis() {
	// printf("finParentesis\n");
	completarToken(1, FINPARENTESIS);
}

int crearTerceto(char * op1, char *op2, char *op3) {

	struct strTerceto terceto;
	
	contadorTercetos++;
	
	terceto.numero = contadorTercetos;
	strcpy(terceto.elem1, op1);
	strcpy(terceto.elem2, op2);
	strcpy(terceto.elem3, op3);
	listaTercetos[contadorTercetos] = terceto;
	
	return contadorTercetos;
}

void guardarTercetos() {
	
	int it = 1;
	int jt = 1;
	int kt = 1;
	int nroDeprecado = -1;
	struct strTerceto terceto;
	int listaTercetosDeprecados[100];
	int contadorTercetosDeprecados = 0;
	char indiceTerceto[100];
	struct strTablaSimbolos auxiliarTS;
	int indiceTS = 0;

	
	//Abrir archivo para guardar los tercetos
	if ((salidaTercetos = abrirArchivo("Intermedia.txt", 'E')) == NULL) {
		printf("ERROR: No se pudo abrir el archivo de salida de tercetos.\n");
	}
	
	//Recorro todos los tercetos eliminando los alias de las variables renombradas.
	//Busco en TS aquellos simbolos que fueron renombrados
	for(it = 0; it < posUltimoSimbolo ; it++)
	{	//Si el simbolo fue renombrado
		if(strcmp(tablaSimbolos[it].rename, "-") != 0)
		{	//Recorro todos los tercetos buscando por el simbolo renombrado y le cambio el valor por el original.
			for(kt = 1; kt <= contadorTercetos ; kt++){

				if ( strcmp(listaTercetos[kt].elem1, tablaSimbolos[it].rename ) == 0 ) 
					strcpy(listaTercetos[kt].elem1, buscarTSPorAlias(tablaSimbolos[it].rename));
					
				if ( strcmp(listaTercetos[kt].elem2, tablaSimbolos[it].rename ) == 0 ) 
					strcpy(listaTercetos[kt].elem2, buscarTSPorAlias(tablaSimbolos[it].rename));
					
				if ( strcmp(listaTercetos[kt].elem3, tablaSimbolos[it].rename ) == 0 ) 
					strcpy(listaTercetos[kt].elem3, buscarTSPorAlias(tablaSimbolos[it].rename));	
			}		
		}		
	}
	
	
	//hacemos una pseudo optimizacion reemplazando los tercetos vacios.	
	//primero: seleccionamos todos los tercetos con un solo elemento (cte y var) y guardamos el indice
	for(it = 1; it <= contadorTercetos ; it++){

		if ( strcmp(listaTercetos[it].elem2, "---") == 0 && strcmp(listaTercetos[it].elem3, "---") == 0) {
				
			listaTercetos[it].deprecated = 1;
			listaTercetosDeprecados[contadorTercetosDeprecados] = listaTercetos[it].numero;
			contadorTercetosDeprecados++;
		}
	}
	
	//segundo: recorremos los elementos deprecados y los reemplazamos donde se esten usando
	for(jt = 0; jt <= contadorTercetosDeprecados ; jt++){
		
		nroDeprecado = listaTercetosDeprecados[jt];
		sprintf(indiceTerceto,"[%i]",nroDeprecado);
		
		for(it = 1; it <= contadorTercetos ; it++){
			
			terceto.numero = listaTercetos[it].numero;
			strcpy(terceto.elem1, listaTercetos[it].elem1);
			strcpy(terceto.elem2, listaTercetos[it].elem2);
			strcpy(terceto.elem3, listaTercetos[it].elem3);
			terceto.deprecated = listaTercetos[it].deprecated;
			
			if(strcmp(listaTercetos[it].elem1,"JLE") != 0 && 
				strcmp(listaTercetos[it].elem1,"JL") != 0 &&
					strcmp(listaTercetos[it].elem1,"JGE") != 0 &&
						strcmp(listaTercetos[it].elem1,"JG") != 0 &&
							strcmp(listaTercetos[it].elem1,"JE") != 0 && 
								strcmp(listaTercetos[it].elem1,"JNE") != 0 && 
									strcmp(listaTercetos[it].elem1,"JI") != 0 ){
									
										if ( strcmp(listaTercetos[it].elem1, indiceTerceto) == 0 ) {
											strcpy(terceto.elem1, listaTercetos[nroDeprecado].elem1);
										}
										if ( strcmp(listaTercetos[it].elem2, indiceTerceto) == 0 ) {
											strcpy(terceto.elem2, listaTercetos[nroDeprecado].elem1);
										}
										if ( strcmp(listaTercetos[it].elem3, indiceTerceto) == 0 ) {
											strcpy(terceto.elem3, listaTercetos[nroDeprecado].elem1);
										}	
										
			}else{
				
				if ( strcmp(listaTercetos[it].elem2, indiceTerceto) == 0 ) {
						listaTercetos[nroDeprecado].deprecated = 0;
				}
				if ( strcmp(listaTercetos[it].elem3, indiceTerceto) == 0 ) {
						listaTercetos[nroDeprecado].deprecated = 0;
				}
			}
			
			listaTercetos[it] = terceto;
		}
	}
	
	//tercero: generamos auxiliares en la TS para soportar los resultados de los tercetos

	strcpy(auxiliarTS.tipo, "FLOAT");
	auxiliarTS.tipoToken = FLOAT;	
	auxiliarTS.longitud = 0;
	sprintf(auxiliarTS.valor,"-");
		
	for(it = 1; it <= contadorTercetos ; it++){

		if ( strcmp(listaTercetos[it].elem1, "*") == 0 || strcmp(listaTercetos[it].elem1, "/") == 0 || strcmp(listaTercetos[it].elem1, "+") == 0 || strcmp(listaTercetos[it].elem1, "-") == 0 || strcmp(listaTercetos[it].elem1, "ROUND") == 0 || strcmp(listaTercetos[it].elem1, "TRUNC") == 0) {	
			sprintf(auxiliarTS.nombre,"_AUX%i",listaTercetos[it].numero);
						printf("agregando aux al TS %s",auxiliarTS.nombre);
			indiceTS = agregarTS(auxiliarTS);
			tablaSimbolos[indiceTS].declarada = 1;
		}
	}
	
	
	
	
	for(it = 1; it <= contadorTercetos; it++){
		
		if(listaTercetos[it].deprecated != 1){
			fprintf(salidaTercetos, "%d (%s | %s | %s)\n",listaTercetos[it].numero,listaTercetos[it].elem1,listaTercetos[it].elem2,listaTercetos[it].elem3);
		}
	}
	
	fclose(salidaTercetos);
}

void resolverUltimoCondicional(int nroOp, char *op) {
	
	int it = contadorTercetos;
	int continuar = 1;
	struct strTerceto terceto;
	
	//TODO REFACTORIZAR
	
	if (nroOp == 2){
		
		for(it = contadorTercetos; it >= 1 && continuar == 1; it--){

			if ( strcmp(listaTercetos[it].elem2, "*REEMPLAZAR") == 0) {
				continuar = 0;
				terceto.numero = listaTercetos[it].numero;
				strcpy(terceto.elem1, listaTercetos[it].elem1);
				strcpy(terceto.elem2, op);
				strcpy(terceto.elem3, listaTercetos[it].elem3);
				listaTercetos[it] = terceto;
			}
		}
		
	}else{ //3
		
		for(it = contadorTercetos; it >= 1 && continuar == 1; it--){

			if ( strcmp(listaTercetos[it].elem3, "*REEMPLAZAR") == 0) {
				continuar = 0;
				terceto.numero = listaTercetos[it].numero;
				strcpy(terceto.elem1, listaTercetos[it].elem1);
				strcpy(terceto.elem2, listaTercetos[it].elem2);
				strcpy(terceto.elem3, op);
				listaTercetos[it] = terceto;
			}
		}
		
	}
	
}

void apilarNroTerceto(int nroTerceto){
//	printf("apilarNroTerceto %d",nroTerceto);
	indicePilaTercetos ++;
	pilaTercetos[indicePilaTercetos] = nroTerceto;
}

int desapilarNroTerceto(){
	indicePilaTercetos --;
//	printf("desapilarNroTerceto %d",pilaTercetos[indicePilaTercetos+1]);
	return pilaTercetos[indicePilaTercetos+1];
}


char * negarComparador (char * comparador) {
	
	if(strcmp("JLE",comparador) == 0){ //mayor
		return "JG";
	}else if(strcmp("JL",comparador) == 0){  // mayorigual
		return "JGE";
	}else if(strcmp("JGE",comparador) == 0){  // menor
		return "JL";
	}else if(strcmp("JG",comparador) == 0){  // menorigual
		return "JLE";
	}else if(strcmp("JE",comparador) == 0){  // distinto
		return "JNE";
	}else if(strcmp("JNE",comparador) == 0){  // igual
		return "JE";
	}else{
		return "ERROR NEGACION";
	}
	
}


void generarAssembler(){

	FILE *fileAssembler;

	//Abrir archivo para generar el assembler
	if((fileAssembler = abrirArchivo("final.asm", 'E')) == NULL) {
		printf("No se pudo abrir el archivo final.asm de assembler.\n");
	}

	//Encabezado del archivo
	fprintf (fileAssembler, ".MODEL LARGE\n"); //Tipo del modelo de memoria usado
	fprintf (fileAssembler, ".386\n" );
	fprintf (fileAssembler, ".STACK 200h\n\n"); //Bytes en el stack
	fprintf (fileAssembler, "MAXTEXTSIZE equ 50\n"); //Tamanio variables string x default
	
	//.DATA
	agregarSeccionDataASM(fileAssembler);
	
	//.CODE
	agregarSeccionCodeASM(fileAssembler);
	
	//.END
	fprintf (fileAssembler, "\n\nCALL PAUSA");
  	fprintf (fileAssembler, "\n\nmov ax,4C00h"); //Indica que debe terminar la ejecución
  	fprintf (fileAssembler, "\nint 21h \n");
	addRutines(fileAssembler);
  	fprintf(fileAssembler, "\nEND");
  	fclose(fileAssembler);
}



void agregarSeccionDataASM (FILE *fileAssembler) {

	int i;

	//Comienzan las declaraciones
  	fprintf (fileAssembler, "\n.DATA\n");

	//Se obtienen las variables de la TS
	for(i = 0; i < posUltimoSimbolo; i++) {
   	
		if(strcmp(tablaSimbolos[i].tipo,"FLOAT") == 0) {
     		fprintf(fileAssembler, "\n\t%s\tdd\t?", tablaSimbolos[i].nombre);
      	}

      	if(strcmp(tablaSimbolos[i].tipo,"ENTERO") == 0) {
			fprintf(fileAssembler, "\n\t%s\tdd\t?", tablaSimbolos[i].nombre);
      	}

   		if(strcmp(tablaSimbolos[i].tipo,"STRING") == 0) {
			fprintf(fileAssembler, "\n\t%s\tdb 0Dh, 0Ah, MAXTEXTSIZE dup (?), '$'", tablaSimbolos[i].nombre);
		}

		if(strcmp(tablaSimbolos[i].tipo,"CTE_STRING") == 0) {
         	fprintf(fileAssembler, "\n\t%s\tdb 0Dh, 0Ah, %s, '$', %d dup (?)", tablaSimbolos[i].nombre, tablaSimbolos[i].valor, tablaSimbolos[i].longitud);
		}

		if(strcmp(tablaSimbolos[i].tipo,"CTE_FLOAT") == 0) {
         	fprintf(fileAssembler, "\n\t%s\tdd\t%f", tablaSimbolos[i].nombre, atof(tablaSimbolos[i].valor));
		}

      	if(strcmp(tablaSimbolos[i].tipo,"CTE_INT") == 0) {
         	fprintf(fileAssembler, "\n\t%s\tdd\t%f", tablaSimbolos[i].nombre, atof(tablaSimbolos[i].valor));
		}
		
		if(strcmp(tablaSimbolos[i].tipo,"CTE_BASE_16") == 0) {
         	fprintf(fileAssembler, "\n\t%s\tdd\t%f", tablaSimbolos[i].nombre, atof(tablaSimbolos[i].valor));
		}
		
		if(strcmp(tablaSimbolos[i].tipo,"CTE_BASE_2") == 0) {
         	fprintf(fileAssembler, "\n\t%s\tdd\t%f", tablaSimbolos[i].nombre, atof(tablaSimbolos[i].valor));
		}
		
	 }
   	
	//auxiliares para las rutinas	
	fprintf(fileAssembler, "\n\t_TRUNCVAL\tdD\t1.000000");
	fprintf(fileAssembler, "\n\t_PESTADO\tdw\t?");
	fprintf(fileAssembler, "\n\t_AUXSTR\tdb 0Dh, 0Ah, MAXTEXTSIZE dup (?), '$'" );
	fprintf(fileAssembler, "\n\tmsgPRESIONE\tdb\t0DH,0AH,\"Presione una tecla para continuar...\",'$'");
	fprintf(fileAssembler, "\n\t_NEWLINE\tdb\t0Dh,0Ah,'$'");
	fprintf(fileAssembler, "\n\t_BUF\tdb\t50 dup (?),'$'");
	fprintf(fileAssembler, "\n\t_BUF_LEN equ 13");
	fprintf(fileAssembler, "\n\t_BUF_PTO equ 9");
	

}

void agregarSeccionCodeASM (FILE *fileAssembler) {
	
	int it = 0;
	int ij = 0;
	int iContinuar = 1;
	int concat = 0;
	int indiceTSTerceto = -1;
	int listaTercetosEtiquetar[500];
	int listaTercetosEtiquetarIndice = 0;
   int indiceTSTerceto3;
	int elem = -1;
	
	fprintf (fileAssembler, "\n\n.CODE"); 
	fprintf (fileAssembler, "\n\tmov AX,@DATA"); //Inicializa el segmento de datos
	fprintf (fileAssembler, "\n\tmov DS,AX");
    fprintf (fileAssembler, "\n\tmov ES,AX\n");
	fprintf (fileAssembler, "\n\tFINIT\n");



	//antes de procesar los tercetos, generamos un listado de los tercetos que necesitan etiquetas
	for(it = 1; it <= contadorTercetos ; it++){
		
		if(strcmp(listaTercetos[it].elem1,"JLE") == 0 || 
			strcmp(listaTercetos[it].elem1,"JL") == 0 ||
				strcmp(listaTercetos[it].elem1,"JGE") == 0 ||
					strcmp(listaTercetos[it].elem1,"JG") == 0 ||
						strcmp(listaTercetos[it].elem1,"JE") == 0 || 
							strcmp(listaTercetos[it].elem1,"JNE") == 0 || 
								strcmp(listaTercetos[it].elem1,"JI") == 0 ){
			
									elem = convertirNroTercetoEnEntero(listaTercetos[it].elem2);
									listaTercetosEtiquetar[listaTercetosEtiquetarIndice] = elem;
									listaTercetosEtiquetarIndice++;
					
									elem = convertirNroTercetoEnEntero(listaTercetos[it].elem3);
									listaTercetosEtiquetar[listaTercetosEtiquetarIndice] = elem;
									listaTercetosEtiquetarIndice++;
		}	
	}

	//procesamos todos los tercetos
	for(it = 1; it <= contadorTercetos ; it++){

		if ( listaTercetos[it].deprecated != 1 ) {
			
			//creacion de etiquetas para el terceto de ser necesario
			iContinuar = 1;
			for(ij = 0; ij <= listaTercetosEtiquetarIndice && iContinuar==1; ij++){
				if(listaTercetos[it].numero == listaTercetosEtiquetar[ij]){
					iContinuar = 0;
					fprintf (fileAssembler, "\nSALTO%d:\n",listaTercetosEtiquetar[ij]);
				}
			}
			
			if(strcmp(listaTercetos[it].elem1,"CMP") == 0){
				fprintf (fileAssembler, "\n\tffree st(0)");
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
				fprintf (fileAssembler, "\n\tfxch");
           		fprintf (fileAssembler, "\n\tfcomp");
           		fprintf (fileAssembler, "\n\tfstsw ax");
				fprintf (fileAssembler, "\n\tfwait");
           		fprintf (fileAssembler, "\n\tsahf");
			}
			
			if(strcmp(listaTercetos[it].elem1,"JLE") == 0){	
				fprintf (fileAssembler, "\n\tjbe SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem3));
			}
			
			if(strcmp(listaTercetos[it].elem1,"JL") == 0){	
				fprintf (fileAssembler, "\n\tjb SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem3));
			}
			
			if(strcmp(listaTercetos[it].elem1,"JGE") == 0){	
				fprintf (fileAssembler, "\n\tjae SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem3));
			}
			
			if(strcmp(listaTercetos[it].elem1,"JG") == 0){	
				fprintf (fileAssembler, "\n\tja SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem3));
			}
			
			if(strcmp(listaTercetos[it].elem1,"JE") == 0){	
				fprintf (fileAssembler, "\n\tje SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem3));
			}
			
			if(strcmp(listaTercetos[it].elem1,"JNE") == 0){	
				fprintf (fileAssembler, "\n\tjne SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem3));
			}
				
			if(strcmp(listaTercetos[it].elem1,"JI") == 0){	
				fprintf (fileAssembler, "\n\tjmp SALTO%d", convertirNroTercetoEnEntero(listaTercetos[it].elem2));
			}		
			
			
			if(strcmp(listaTercetos[it].elem1,"+") == 0){

				indiceTSTerceto = tercetoDevolverPosicionTS(listaTercetos[it].elem2);
				indiceTSTerceto3 = tercetoDevolverPosicionTS(listaTercetos[it].elem3);

				if(tablaSimbolos[indiceTSTerceto].tipoToken == STRING || tablaSimbolos[indiceTSTerceto3].tipoToken == STRING){
					concat = 1;
					//copiamos la primera cadena a la var auxiliar
					fprintf (fileAssembler, "\n\tmov si,OFFSET %s",convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
					fprintf (fileAssembler, "\n\tmov di,OFFSET _AUXSTR");
					fprintf (fileAssembler, "\n\tcall COPIAR\n");
					//concatenamos la segunda cadena al aux
					fprintf (fileAssembler, "\n\tmov si,OFFSET %s",convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
					fprintf (fileAssembler, "\n\tmov di,OFFSET _AUXSTR");
					fprintf (fileAssembler, "\n\tcall CONCAT\n");
					
				}else{
					concat = 0;
					fprintf (fileAssembler, "\n\tffree st(0)");
					fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
					fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
					fprintf (fileAssembler, "\n\tfadd");
					//guardamos el resultado en _AUX
					fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);
				}
				
				
			}
			
			
			if(strcmp(listaTercetos[it].elem1,"-") == 0){
				fprintf (fileAssembler, "\n\tffree st(0)");
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
				fprintf (fileAssembler, "\n\tfsub");
				//guardamos el resultado en _AUX
				fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);
			}
			
			if(strcmp(listaTercetos[it].elem1,"*") == 0){
				fprintf (fileAssembler, "\n\tffree st(0)");
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
				fprintf (fileAssembler, "\n\tfmul");
				//guardamos el resultado en _AUX
				fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);
			}
			
			if(strcmp(listaTercetos[it].elem1,"/") == 0){
				fprintf (fileAssembler, "\n\tffree st(0)");
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
				fprintf (fileAssembler, "\n\tfdiv");
				//guardamos el resultado en _AUX
				fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);
			}
			
			if(strcmp(listaTercetos[it].elem1,"ROUND") == 0){
				//setteamos la palabra de estado del copro para llenar los flags de round _PESTADO
				/*
				fprintf (fileAssembler, "\n\txor eax,eax");
				fprintf (fileAssembler, "\n\tfstcw _PESTADO");
				fprintf (fileAssembler, "\n\tfwait");
				fprintf (fileAssembler, "\n\tmov ax,_PESTADO");
				fprintf (fileAssembler, "\n\tor ax, 0000100000000000b"); //fija el redondeo de los bits a 10 (round)
				fprintf (fileAssembler, "\n\tmov _PESTADO,ax");
				fprintf (fileAssembler, "\n\tfldcw _PESTADO");
				*/
				fprintf (fileAssembler, "\n\tffree st(0)");
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				fprintf (fileAssembler, "\n\tfrndint");
				//guardamos el resultado en _AUX
				fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);
			}
			
			if(strcmp(listaTercetos[it].elem1,"TRUNC") == 0){
				//setteamos la palabra de estado del copro para llenar los flags de round _PESTADO				
				fprintf (fileAssembler, "\n\txor eax,eax");
				fprintf (fileAssembler, "\n\tfstcw _PESTADO");
				fprintf (fileAssembler, "\n\tfwait");
				fprintf (fileAssembler, "\n\tmov ax,_PESTADO");
				fprintf (fileAssembler, "\n\tor ax, 0000100000000000b"); //fija el redondeo de los bits a 10 (round)
				fprintf (fileAssembler, "\n\tmov _PESTADO,ax");
				fprintf (fileAssembler, "\n\tfldcw _PESTADO");		
				
				fprintf (fileAssembler, "\n\tffree st(0)");
				fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				fprintf (fileAssembler, "\n\tfrndint");
				//guardamos el resultado en _AUX
				fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);
				fprintf (fileAssembler, "\n\tffree st(0)");
				//Vuelvo a cargar el terceto
				fprintf (fileAssembler, "\n\tfld _AUX%d", listaTercetos[it].numero);
				//Cargo la variable que contiene el -1 en assembler y hago la resta.
				fprintf (fileAssembler, "\n\tfld _TRUNCVAL");
				fprintf (fileAssembler, "\n\tfsub");
				fprintf (fileAssembler, "\n\tfstp _AUX%d", listaTercetos[it].numero);				
				
			}
			
			if(strcmp(listaTercetos[it].elem1,"IGUAL") == 0){
				
				indiceTSTerceto = tercetoDevolverPosicionTS(listaTercetos[it].elem2);
				if(tablaSimbolos[indiceTSTerceto].tipoToken == STRING ){
					
					if(concat == 1){
						// apunta el origen 
			    		fprintf (fileAssembler, "\n\tmov si,OFFSET %s","_AUXSTR");
					}else{
						// apunta el origen 
			    		fprintf (fileAssembler, "\n\tmov si,OFFSET %s",convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
					}
		      		//apunta el destino 
		      		fprintf (fileAssembler, "\n\tmov di,OFFSET %s",convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
		      		fprintf (fileAssembler, "\n\tcall COPIAR\n");
					
					
				}else{
					fprintf (fileAssembler, "\n\tffree st(0)");
					fprintf (fileAssembler, "\n\tfld %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem3));
					fprintf (fileAssembler, "\n\tfstp %s", convertirNroTercetoEnAuxiliar(listaTercetos[it].elem2));
				}
				
			}
			
			if(strcmp(listaTercetos[it].elem1,"PRINT") == 0){
				
				indiceTSTerceto = tercetoDevolverPosicionTS(listaTercetos[it].elem2);
				if(tablaSimbolos[indiceTSTerceto].tipoToken == STRING ){
					fprintf (fileAssembler, "\n\tmov DX, OFFSET %s", listaTercetos[it].elem2);
					fprintf (fileAssembler, "\n\tmov ah, 9"); //AH=9 es el servicio de impresion
					fprintf (fileAssembler, "\n\tint 21h");
				}else{					
					fprintf (fileAssembler, "\n\tmov si,OFFSET %s",listaTercetos[it].elem2);
					fprintf (fileAssembler, "\n\tmov di,OFFSET _BUF");
					fprintf (fileAssembler, "\n\tcall ImprimirReal");
				}
				
				
			}
	
		}
	}
	
	fprintf (fileAssembler, "\nSALTO%d:\n",contadorTercetos+1);
}

int tercetoDevolverPosicionTS(char * elemTerceto){

	int i = 0;
	
	for (i = 0; i < posUltimoSimbolo; i++) {
		
		if (strcmp (tablaSimbolos[i].nombre,elemTerceto) == 0 ){
			return i;
		}
	}
	
	return -1;
}


char* convertirNroTercetoEnAuxiliar(char * elemTerceto){	
	
	
	int i = 0;
	int peso = strlen(elemTerceto);
	
	//si es un [x]
	if(elemTerceto[0] == '['){
		
		for(i = 1; i < peso-1; i++){
			auxiliar[i-1]=elemTerceto[i];
		}
		auxiliar[i-1]='\0';
		sprintf(resultado,"_AUX%s",auxiliar);
		return resultado;
	}
	
	return elemTerceto;
}

//devuelve un numero de terceto ([X]) como INT 
int convertirNroTercetoEnEntero(char * elemTerceto){
	
	char auxiliar[50];
	int i = 0;
	int peso = strlen(elemTerceto);
	
	//si es un [x]
	if(elemTerceto[0] == '['){
		
		for(i = 1; i < peso-1; i++){
			auxiliar[i-1]=elemTerceto[i];
		}
		auxiliar[i-1]='\0';
		return atoi(auxiliar);
	}
	return -1;
}



void addRutines(FILE *fileAssembler) {
    

	fprintf (fileAssembler, "\n\n;************************************************************\n" );
	fprintf (fileAssembler,	"; Imprimir un numero flotante\n" );
	fprintf (fileAssembler,	";\n" );
	fprintf (fileAssembler,	"ImprimirReal:\n" );
	fprintf (fileAssembler,	"\tpush di\n" );
	fprintf (fileAssembler,	"\tmov cx,_BUF_LEN\n" );
	fprintf (fileAssembler,	"\tmov al,byte ptr ' '\n" );
	fprintf (fileAssembler,	"\trep stosb\n" );
	fprintf (fileAssembler,	"\tmov [di],byte ptr '$'\n" );
	fprintf (fileAssembler,	"\tpop di\n" );
	fprintf (fileAssembler,	"\tpush di\n" );
	fprintf (fileAssembler,	"\tmov byte ptr [di],al\n" );
	fprintf (fileAssembler,	"\tmov byte ptr [di+_BUF_PTO],byte ptr '.'\n" );
	fprintf (fileAssembler,	"\tcall getExponente\n" );
	fprintf (fileAssembler,	"\tmov bx,ax\n" );
	fprintf (fileAssembler,	"\tcall getMantisa\n" );
	fprintf (fileAssembler,	"\tpush eax\n" );
	fprintf (fileAssembler,	"\tmov cl,10d\n" );
	fprintf (fileAssembler,	"\tshr eax,cl\n" );
	fprintf (fileAssembler,	"\tadd di,_BUF_PTO-1\n" );
	fprintf (fileAssembler,	"\tcall format9\n" );
	fprintf (fileAssembler,	"\tpop eax\n" );
	fprintf (fileAssembler,	"\tand eax,003FFFFh\n" );
	fprintf (fileAssembler,	"\tcall convDecimal\n" );
	fprintf (fileAssembler,	"\tpop di\n" );
	fprintf (fileAssembler,	"\tadd di,_BUF_PTO+3\n" );
	fprintf (fileAssembler,	"\tmov cx,3\n" );
	fprintf (fileAssembler,	"\tcall formatX\n" );
	fprintf (fileAssembler,	"\tmov AH,09H\n" );
	fprintf (fileAssembler,	"\tmov dx, OFFSET _BUF\n" );
	fprintf (fileAssembler,	"\tint 21h\n" );
    fprintf (fileAssembler,	"\tmov DX, OFFSET _NEWLINE\n" );
    fprintf (fileAssembler,	"\tmov ah,09\n" );
    fprintf (fileAssembler,	"\tint 21h\n" );
	fprintf (fileAssembler,	"\tret\n\n" );
	
	
	fprintf (fileAssembler,	"cSPos:\n" );
		fprintf (fileAssembler,	"\tmov al,'+'\n" );
	fprintf (fileAssembler,	"csEnd:\n" );
		fprintf (fileAssembler,	"\tret\n" );

	fprintf (fileAssembler,	"getExponente:\n" );
		fprintf (fileAssembler,	"\tmov ax,[si+2]\n" );
		fprintf (fileAssembler,	"\tshl ax,1\n" );
		fprintf (fileAssembler,	"\txchg al,ah\n" );
		fprintf (fileAssembler,	"\tand ax,000FFh\n" );
		fprintf (fileAssembler,	"\tadd eax,0FF81h\n" );
		fprintf (fileAssembler,	"\tret\n" );
	
	fprintf (fileAssembler,	"getMantisa:\n" );
		fprintf (fileAssembler,	"\tmov eax,[si]\n" );
		fprintf (fileAssembler,	"\tand eax,007FFFFFh\n" );
		fprintf (fileAssembler,	"\tor eax,00800000h\n" );
		fprintf (fileAssembler,	"\tmov cx,13d\n" );
		fprintf (fileAssembler,	"\tsub cx,bx\n" );
		fprintf (fileAssembler,	"\tjns gM01\n" );
		fprintf (fileAssembler,	"\tneg cx\n" );
		fprintf (fileAssembler,	"\tshl eax,cl\n" );
		fprintf (fileAssembler,	"\tjmp gMend\n" );
	fprintf (fileAssembler,	"gM01:\n" );
		fprintf (fileAssembler,	"\tclc\n" );
		fprintf (fileAssembler,	"\tshr eax,cl\n" );
	fprintf (fileAssembler,	"gMend:\n" );
		fprintf (fileAssembler,	"\tret\n" );
		
		
		
		
		
		
		fprintf (fileAssembler,	"formatear:\n" );
		fprintf (fileAssembler,	"format9:\n" );
			fprintf (fileAssembler,	"\tmov edx,eax\n" );
			fprintf (fileAssembler,	"\tmov cl,16\n" );
			fprintf (fileAssembler,	"\tshr edx,cl ; genero DX:AX\n" );
			fprintf (fileAssembler,	"\tmov bx,10000\n" );
			fprintf (fileAssembler,	"\tdiv bx ; ax resultado, dx, reminder\n" );
			fprintf (fileAssembler,	"\tpush ax\n" );
			fprintf (fileAssembler,	"\tmov bx,10\n" );
			fprintf (fileAssembler,	"\tmov ax,dx\n" );
			fprintf (fileAssembler,	"\tmov cl,4\n" );
		fprintf (fileAssembler,	"fCiclo01:\n" );
			fprintf (fileAssembler,	"\txor dx,dx\n" );
			fprintf (fileAssembler,	"\tidiv bx\n" );
			fprintf (fileAssembler,	"\tadd dl,'0'\n" );
			fprintf (fileAssembler,	"\tmov es:[di],dl\n" );
			fprintf (fileAssembler,	"\tsub di,1\n" );
			fprintf (fileAssembler,	"\tsub cl,1\n" );
			fprintf (fileAssembler,	"\tjne fCiclo01\n" );
			fprintf (fileAssembler,	"\tpop ax\n" );
			fprintf (fileAssembler,	"\tmov cl,3\n" );
		fprintf (fileAssembler,	"formatX:\n" );
			fprintf (fileAssembler,	"\tmov bx,10\n" );
		fprintf (fileAssembler,	"fCiclo02:\n" );
			fprintf (fileAssembler,	"\txor dx,dx\n" );
			fprintf (fileAssembler,	"\tidiv bx\n" );
			fprintf (fileAssembler,	"\tadd dl,'0'\n" );
			fprintf (fileAssembler,	"\tmov es:[di],dl\n" );
			fprintf (fileAssembler,	"\tsub di,1\n" );
			fprintf (fileAssembler,	"\tsub cl,1\n" );
			fprintf (fileAssembler,	"\tjnz fCiclo02\n" );
			fprintf (fileAssembler,	"\tret\n" );
			fprintf (fileAssembler,	"\tnumeros dw 500,250,125,62,31,15,8,4,2,1\n" );

		fprintf (fileAssembler,	"convDecimal:\n" );
			fprintf (fileAssembler,	"\tmov cx,09\n" );
			fprintf (fileAssembler,	"\txor bx,bx\n" );
			fprintf (fileAssembler,	"\txor dx,dx\n" );
			fprintf (fileAssembler,	"\tclc\n" );
		fprintf (fileAssembler,	"cvCiclo:\n" );
			fprintf (fileAssembler,	"\tshr ax,1\n" );
			fprintf (fileAssembler,	"\tjnc cvCiclo01\n" );
			fprintf (fileAssembler,	"\tmov bx,cx\n" );
			fprintf (fileAssembler,	"\tshl bx,1\n" );
			fprintf (fileAssembler,	"\tadd bx,offset numeros\n" );
			fprintf (fileAssembler,	"\tmov bx,cs:[bx]\n" );
			fprintf (fileAssembler,	"\tadd bx,dx\n" );
			fprintf (fileAssembler,	"\tmov dx,bx\n" );
		fprintf (fileAssembler,	"cvCiclo01:\n" );
			fprintf (fileAssembler,	"\tsub cx,1\n" );
			fprintf (fileAssembler,	"\tjns cvCiclo\n" );
			fprintf (fileAssembler,	"\tmov ax,dx\n" );
			fprintf (fileAssembler,	"\tadd ax,1\n" );
			fprintf (fileAssembler,	"\tret\n" );
			
			fprintf (fileAssembler,	"PAUSA:\n" );
			    fprintf (fileAssembler,	"\tmov DX, OFFSET _NEWLINE\n" );
			    fprintf (fileAssembler,	"\tmov ah,09\n" );
			    fprintf (fileAssembler,	"\tint 21h\n" );
			    fprintf (fileAssembler,	"\tmov dx,OFFSET msgPRESIONE\n" );
			    fprintf (fileAssembler,	"\tmov ah,09\n" );
			    fprintf (fileAssembler,	"\tint 21h\n" );
			    fprintf (fileAssembler,	"\tmov ah, 1\n" );
			    fprintf (fileAssembler,	"\tint 21h\n" );
			    fprintf (fileAssembler,	"\tret\n" );
	


	fprintf (fileAssembler, "\n\n;************************************************************\n" );
	fprintf (fileAssembler,	"; devuelve en BX la cantidad de caracteres que tiene un string\n" );
	fprintf (fileAssembler,	"; DS:SI apunta al string.\n" );
	fprintf (fileAssembler,	";\n" );
	fprintf (fileAssembler,	"STRLEN PROC near\n" );
	fprintf (fileAssembler,	"\tmov bx,0\n" );
    fprintf (fileAssembler,	"STRL01:\n");
	fprintf (fileAssembler,	"\tcmp BYTE PTR [SI+BX],'$'\n" );
	fprintf (fileAssembler,	"\tje STREND\n" );
	fprintf (fileAssembler,	"\tinc BX\n" );
	fprintf (fileAssembler,	"\tjmp STRL01\n" );
	fprintf (fileAssembler,	"STREND:\n" );
	fprintf (fileAssembler,	"\tret\n" );
	fprintf (fileAssembler,	"\tSTRLEN ENDP\n" );
	fprintf (fileAssembler,	"\n;*********************************************************************\n" );
	fprintf (fileAssembler,	"; copia DS:SI a ES:DI; busca la cantidad de caracteres\n" );
	fprintf (fileAssembler,	";\n" );
	fprintf (fileAssembler,	"COPIAR PROC near\n" );
	fprintf (fileAssembler,	"\tcall STRLEN           ; busco la cantidad de caracteres\n" );
	fprintf (fileAssembler,	"\tcmp bx,MAXTEXTSIZE\n" );
	fprintf (fileAssembler,	"\tjle COPIARSIZEOK\n" );
	fprintf (fileAssembler,	"\tmov bx,MAXTEXTSIZE\n" );
	fprintf (fileAssembler,	"COPIARSIZEOK:\n" );
	fprintf (fileAssembler,	"\tmov cx,bx           ; la copia se hace de 'CX' caracteres\n" );
	fprintf (fileAssembler,	"\tcld             ; cld es para que la copia se realice\n" );
	fprintf (fileAssembler,	"\t; hacia adelante\n" );
	fprintf (fileAssembler,	"\trep movsb           ; copia la cadea\n" );
	fprintf (fileAssembler,	"\tmov al,'$'           ; carácter terminador\n" );
	fprintf (fileAssembler,	"\tmov BYTE PTR [DI],al        ; el registro DI quedo apuntando al\n" );
	fprintf (fileAssembler,	"\t; final\n" );
	fprintf (fileAssembler,	"\tret\n" );
	fprintf (fileAssembler,	"COPIAR ENDP\n" );
	fprintf (fileAssembler,	"\n;*******************************************************\n" );
	fprintf (fileAssembler,	"; concatena DS:SI al final de ES:DI.\n" );
	fprintf (fileAssembler,	";\n" );
	fprintf (fileAssembler,	"; busco el size del primer string\n" );
	fprintf (fileAssembler,	"; sumo el size del segundo string\n" );
	fprintf (fileAssembler,	"; si la suma excede MAXTEXTSIZE, copio solamente MAXTEXTSIZE caracteres\n" );
	fprintf (fileAssembler,	"; si la suma NO excede MAXTEXTSIZE, copio el total de caracteres que tiene el segundo string\n" );
	fprintf (fileAssembler,	";\n" );
	fprintf (fileAssembler,	"CONCAT PROC near\n" );
	fprintf (fileAssembler,	"\tpush ds\n" );
	fprintf (fileAssembler,	"\tpush si\n" );
	fprintf (fileAssembler,	"\tcall STRLEN           ; busco la cantidad de caracteres del\n" );
	fprintf (fileAssembler,	"\t;2do string\n" );
	fprintf (fileAssembler,	"\tmov dx,bx           ; guardo en DX la cantidad de caracteres\n" );
	fprintf (fileAssembler,	"\t;en el origen.\n" );
	fprintf (fileAssembler,	"\tmov si,di\n" );
	fprintf (fileAssembler,	"\tpush es\n" );
	fprintf (fileAssembler,	"\tpop ds\n" );
	fprintf (fileAssembler,	"\tcall STRLEN           ; tama#o del 1er string\n" );
	fprintf (fileAssembler,	"\tadd di,bx           ; DI ya queda apuntando al final del\n" );
	fprintf (fileAssembler,	"\t;primer string\n" );
	fprintf (fileAssembler,	"\tadd bx,dx           ; tama#o total\n" );
	fprintf (fileAssembler,	"\tcmp bx,MAXTEXTSIZE         ; excede el tama#o maximo?\n" );
	fprintf (fileAssembler,	"\tjg CONCATSIZEMAL\n" );
	fprintf (fileAssembler,	"CONCATSIZEOK:            ; La suma no excede el maximo, copio\n" );
	fprintf (fileAssembler,	"\t; todos\n" );
	fprintf (fileAssembler,	"\tmov cx,dx           ; los caracteres del segundo string.\n" );
	fprintf (fileAssembler,	"\tjmp CONCATSIGO\n" );
	fprintf (fileAssembler,	"CONCATSIZEMAL:           ; La suma de caracteres de los 2 strings\n" );
	fprintf (fileAssembler,	"\t; exceden el maximo\n" );
	fprintf (fileAssembler,	"\tsub bx,MAXTEXTSIZE\n" );
	fprintf (fileAssembler,	"\tsub dx,bx\n" );
	fprintf (fileAssembler,	"\tmov cx,dx           ; copio lo maximo permitido el resto\n" );
	fprintf (fileAssembler,	"\t;se pierde.\n" );
	fprintf (fileAssembler,	"CONCATSIGO:\n" );
	fprintf (fileAssembler,	"\tpush ds\n" );
	fprintf (fileAssembler,	"\tpop es\n" );
	fprintf (fileAssembler,	"\tpop si\n" );
	fprintf (fileAssembler,	"\tpop ds\n" );
	fprintf (fileAssembler,	"\tcld             ; cld es para que la copia se realice\n" );
	fprintf (fileAssembler,	"\t;hacia adelante\n" );
	fprintf (fileAssembler,	"\trep movsb           ; copia la cadea\n" );
	fprintf (fileAssembler,	"\tmov al,'$'           ; carácter terminador\n");
	fprintf (fileAssembler,	"\tmov BYTE PTR [DI],al        ; el registro DI quedo apuntando al\n");
	fprintf (fileAssembler,	"\t;final\n");
	fprintf (fileAssembler,	"\tret\n");
	fprintf (fileAssembler,	"CONCAT ENDP\n");
}

